123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599(*$ open Ppxlib_cinaps_helpers $*)openImportopenUtilsopenCommonopenWith_errorsmoduleArg=Stdlib.Argletexe_name=Stdlib.Filename.basenameStdlib.Sys.executable_nameletargs=ref[]letadd_argkeyspec~doc=args:=(key,spec,doc)::!argsletloc_fname=refNoneletperform_checks=refOptions.perform_checksletperform_checks_on_extensions=refOptions.perform_checks_on_extensionsletperform_locations_check=refOptions.perform_locations_checkletdebug_attribute_drop=reffalseletapply_list=refNoneletpreprocessor=refNoneletno_merge=reffalseletrequest_print_passes=reffalseletrequest_print_transformations=reffalseletuse_color=reftrueletdiff_command=refOptions.diff_commandletpretty=reffalseletstyler=refNoneletoutput_metadata_filename=refNoneletcorrected_suffix=ref".ppx-corrected"letkeywords=refNoneletraise_embedded_errors_flag=reffalseletghost=objectinheritAst_traverse.mapmethod!locationloc={locwithloc_ghost=true}endletraise_embedded_errors=objectinheritAst_traverse.mapassupermethod!extensionextension=if!raise_embedded_errors_flagthenextension|>Location.Error.of_extension|>Option.iter~f:Location.Error.raise;super#extensionextensionendletchop_prefix~prefixx=ifString.is_prefix~prefixxthenSome(String.drop_prefixx(String.lengthprefix))elseNoneletget_default_path(loc:Location.t)=letfname=loc.loc_start.pos_fnameinmatchchop_prefix~prefix:"./"fnamewith|Somefname->fname|None->fnameletget_default_path_str:structure->string=function|[]->""|{pstr_loc=loc;_}::_->get_default_pathlocletget_default_path_sig:signature->string=function|[]->""|{psig_loc=loc;_}::_->get_default_pathlocmoduleLint_error=structtypet=Location.t*stringletof_stringlocs=(loc,s)endmoduleCookies=structtypet=Tletgiven_through_cli=ref[]letgetTnamepattern=Option.map(Astlib.Ast_metadata.get_cookiename)~f:(fune->lete=Selected_ast.of_ocamlExpressioneinAst_pattern.parsepatterne.pexp_loceFn.id)letget_resTnamepattern=matchOption.map(Astlib.Ast_metadata.get_cookiename)~f:(fune->lete=Selected_ast.of_ocamlExpressioneinAst_pattern.parse_respatterne.pexp_loceFn.id)with|None->OkNone|Some(Oke)->Ok(Somee)|Some(Errore)->ErroreletsetTnameexpr=Astlib.Ast_metadata.set_cookiename(Selected_ast.to_ocamlExpressionexpr)lethandlers=ref[]letadd_handlerf=handlers:=!handlers@[f]letadd_simple_handlernamepattern~f=add_handler(funT->f(getTnamepattern))letacknowledge_cookiesT=List.iter!handlers~f:(funf->fT)letpost_handlers=ref[]letadd_post_handlerf=post_handlers:=!post_handlers@[f]letcall_post_handlersT=List.iter!post_handlers~f:(funf->fT)endmoduleInstrument=structtypepos=Before|Aftertypet={transformation:Expansion_context.Base.t->Parsetree.structure->Parsetree.structureWith_errors.t;position:pos;}moduleV2=structletmaketransformation~position=lettransformationctxst=return(transformationctxst)in{transformation;position}endletmaketransformation~position=lettransformation_st=transformationstinV2.maketransformation~positionendmoduleTransform=structtypet={name:string;aliases:stringlist;impl:(Expansion_context.Base.t->Parsetree.structure->Parsetree.structureWith_errors.t)option;intf:(Expansion_context.Base.t->Parsetree.signature->Parsetree.signatureWith_errors.t)option;lint_impl:(Expansion_context.Base.t->Parsetree.structure->Lint_error.tlist)option;lint_intf:(Expansion_context.Base.t->Parsetree.signature->Lint_error.tlist)option;preprocess_impl:(Expansion_context.Base.t->Parsetree.structure->Parsetree.structureWith_errors.t)option;preprocess_intf:(Expansion_context.Base.t->Parsetree.signature->Parsetree.signatureWith_errors.t)option;enclose_impl:(Expansion_context.Base.t->Location.toption->Parsetree.structure*Parsetree.structure)option;enclose_intf:(Expansion_context.Base.t->Location.toption->Parsetree.signature*Parsetree.signature)option;instrument:Instrument.toption;rules:Context_free.Rule.tlist;registered_at:Caller_id.t;}lethas_nametname=String.equalnamet.name||List.exists~f:(String.equalname)t.aliasesletall:tlistref=ref[]letprint_caller_idoc(caller_id:Caller_id.t)=matchcaller_idwith|None->output_stringoc"<unknown location>"|Someloc->Printf.fprintfoc"%s:%d"loc.filenameloc.line_numberletregister?(extensions=[])?(rules=[])?enclose_impl?enclose_intf?impl?intf?lint_impl?lint_intf?preprocess_impl?preprocess_intf?instrument?(aliases=[])name=letrules=List.mapextensions~f:Context_free.Rule.extension@rulesinletcaller_id=Caller_id.get~skip:[Stdlib.__FILE__]in(matchList.filter!all~f:(funct->has_namectname)with|[]->()|ct::_->Printf.eprintf"Warning: code transformation %s registered twice.\n"name;Printf.eprintf" - first time was at %a\n"print_caller_idct.registered_at;Printf.eprintf" - second time is at %a\n"print_caller_idcaller_id);letimpl=Option.mapimpl~f:(funfctxast->return(fctxast))inletintf=Option.mapintf~f:(funfctxast->return(fctxast))inletpreprocess_impl=Option.mappreprocess_impl~f:(funfctxast->return(fctxast))inletpreprocess_intf=Option.mappreprocess_intf~f:(funfctxast->return(fctxast))inletct={name;aliases;rules;enclose_impl;enclose_intf;impl;intf;lint_impl;preprocess_impl;preprocess_intf;lint_intf;instrument;registered_at=caller_id;}inall:=ct::!allletreclastprevl=matchlwith[]->prev|x::l->lastxlletloc_of_list~get_locl=matchlwith|[]->None|x::l->letfirst:Location.t=get_locxinletlast=get_loc(lastxl)inSome{firstwithloc_end=last.loc_end}letmerge_into_generic_mapperst~embed_errors~hook~expect_mismatch_handler~tool_name~input_name=let{rules;enclose_impl;enclose_intf;impl;intf;_}=tinletmap=newContext_free.map_top_downrules~embed_errors~generated_code_hook:hook~expect_mismatch_handlerinletgen_header_and_footercontextwhole_locf=letheader,footer=fwhole_locin(matchwhole_locwith|Some(loc:Location.t)->(letloc_header={locwithloc_end=loc.loc_start}inletloc_footer={locwithloc_start=loc.loc_end}in(matchheaderwith|[]->()|_->hook.fcontextloc_header(Manyheader));matchfooterwith|[]->()|_->hook.fcontextloc_footer(Manyfooter))|None->(matchheader@footerwith|[]->()|l->letpos={Lexing.pos_fname="";pos_lnum=1;pos_bol=0;pos_cnum=0;}inletloc={Location.loc_start=pos;loc_end=pos;loc_ghost=false}inhook.fcontextloc(Manyl)));(header,footer)inletinput_name=matchinput_namewithSomeinput_name->input_name|None->"_none_"inletmap_implctxtst_with_attrs=letattrs,st=List.split_whilest_with_attrs~f:(function|{pstr_desc=Pstr_attribute_;_}->true|_->false)inletfile_path=get_default_path_strstinletbase_ctxt=Expansion_context.Base.top_level~tool_name~file_path~input_nameinletheader,footer=matchenclose_implwith|None->([],[])|Somef->letwhole_loc=loc_of_listst~get_loc:(funst->st.Parsetree.pstr_loc)ingen_header_and_footerStructure_itemwhole_loc(fbase_ctxt)inmap#structurebase_ctxt(List.concat[attrs;header;st;footer])>>=funst->matchimplwithNone->returnst|Somef->fctxtstinletmap_intfctxtsg_with_attrs=letattrs,sg=List.split_whilesg_with_attrs~f:(function|{psig_desc=Psig_attribute_;_}->true|_->false)inletfile_path=get_default_path_sigsginletbase_ctxt=Expansion_context.Base.top_level~tool_name~file_path~input_nameinletheader,footer=matchenclose_intfwith|None->([],[])|Somef->letwhole_loc=loc_of_listsg~get_loc:(funsg->sg.Parsetree.psig_loc)ingen_header_and_footerSignature_itemwhole_loc(fbase_ctxt)inmap#signaturebase_ctxt(List.concat[attrs;header;sg;footer])>>=funsg->matchintfwithNone->returnsg|Somef->fctxtsgin{twithimpl=Somemap_impl;intf=Somemap_intf}letbuiltin_of_context_free_rewriters~hook~rules~enclose_impl~enclose_intf~input_name=merge_into_generic_mappers~hook~input_name{name="<builtin:context-free>";aliases=[];impl=None;intf=None;lint_impl=None;lint_intf=None;preprocess_impl=None;preprocess_intf=None;enclose_impl;enclose_intf;instrument=None;rules;registered_at=Caller_id.get~skip:[];}letpartition_transformationsts=letbefore_instrs,after_instrs,rest=List.fold_leftts~init:([],[],[])~f:(fun(bef_i,aft_i,rest)t->letreduced_t={twithlint_impl=None;lint_intf=None;preprocess_impl=None;preprocess_intf=None;}inletfinstr=(instr.Instrument.position,instr.Instrument.transformation)inmatchOption.mapt.instrument~fwith|Some(Before,transf)->({reduced_twithimpl=Sometransf;rules=[]}::bef_i,aft_i,reduced_t::rest)|Some(After,transf)->(bef_i,{reduced_twithimpl=Sometransf;rules=[]}::aft_i,reduced_t::rest)|None->(bef_i,aft_i,reduced_t::rest))in(`Linters(List.filter_mapts~f:(funt->ifOption.is_somet.lint_impl||Option.is_somet.lint_intfthenSome{name=Printf.sprintf"<lint:%s>"t.name;aliases=[];impl=None;intf=None;lint_impl=t.lint_impl;lint_intf=t.lint_intf;enclose_impl=None;enclose_intf=None;preprocess_impl=None;preprocess_intf=None;instrument=None;rules=[];registered_at=t.registered_at;}elseNone)),`Preprocess(List.filter_mapts~f:(funt->ifOption.is_somet.preprocess_impl||Option.is_somet.preprocess_intfthenSome{name=Printf.sprintf"<preprocess:%s>"t.name;aliases=[];impl=t.preprocess_impl;intf=t.preprocess_intf;lint_impl=None;lint_intf=None;enclose_impl=None;enclose_intf=None;preprocess_impl=None;preprocess_intf=None;instrument=None;rules=[];registered_at=t.registered_at;}elseNone)),`Before_instrsbefore_instrs,`After_instrsafter_instrs,`Restrest)endmoduleV2=structletregister_transformation=Transform.registerletregister_transformation_using_ocaml_current_ast?impl?intf?aliasesname=letimpl=Option.mapimpl~f:(Ppxlib_ast.Selected_ast.of_ocaml_mapperStructure)inletintf=Option.mapintf~f:(Ppxlib_ast.Selected_ast.of_ocaml_mapperSignature)inregister_transformation?impl?intf?aliasesnameendletadd_ctxt_arg(f:'a->'b):Expansion_context.Base.t->'a->'b=fun_x->fxletregister_transformation?extensions?rules?enclose_impl?enclose_intf?impl?intf?lint_impl?lint_intf?preprocess_impl?preprocess_intf=letimpl=Option.mapimpl~f:add_ctxt_arginletintf=Option.mapintf~f:add_ctxt_arginletpreprocess_impl=Option.mappreprocess_impl~f:add_ctxt_arginletpreprocess_intf=Option.mappreprocess_intf~f:add_ctxt_arginletlint_impl=Option.maplint_impl~f:add_ctxt_arginletlint_intf=Option.maplint_intf~f:add_ctxt_arginletenclose_impl=Option.mapenclose_impl~f:add_ctxt_arginletenclose_intf=Option.mapenclose_intf~f:add_ctxt_arginV2.register_transformation?extensions?rules?enclose_impl?enclose_intf?impl?intf?lint_impl?lint_intf?preprocess_impl?preprocess_intfletregister_code_transformation~name?(aliases=[])~impl~intf=register_transformationname~impl~intf~aliases[@@warning"-16"](* This function triggers a warning 16 as of ocaml 4.12 *)letregister_transformation_using_ocaml_current_ast?impl?intf=letimpl=Option.mapimpl~f:add_ctxt_arginletintf=Option.mapintf~f:add_ctxt_arginV2.register_transformation_using_ocaml_current_ast?impl?intfletdebug_dropped_attributename~old_dropped~new_dropped=letprint_diffwhatab=letdiff=List.filtera~f:(fun(name:_Loc.t)->not(List.existsb~f:(fun(name':_Location.loc)->name.txt==name'.txt)))inifnot(List.is_emptydiff)then(Printf.eprintf"The following attributes %s after applying %s:\n"whatname;List.iterdiff~f:(fun{Location.txt;loc}->Stdlib.Format.eprintf"- %a: %s\n"Location.printloctxt);Stdlib.Format.eprintf"@.")inprint_diff"disappeared"new_droppedold_dropped;print_diff"reappeared"old_droppednew_droppedletget_whole_ast_passes~embed_errors~hook~expect_mismatch_handler~tool_name~input_name=letcts=match!apply_listwith|None->List.rev!Transform.all|Somenames->List.mapnames~f:(funname->List.find!Transform.all~f:(fun(ct:Transform.t)->Transform.has_namectname))inlet(`Linterslinters,`Preprocesspreprocess,`Before_instrsbefore_instrs,`After_instrsafter_instrs,`Restcts)=Transform.partition_transformationsctsin(* Allow only one preprocessor to assure deterministic order *)(ifList.lengthpreprocess>1thenletpp=String.concat~sep:", "(List.mappreprocess~f:(funt->t.name))inleterr=Printf.sprintf"At most one preprocessor is allowed, while got: %s"ppinfailwitherr);letmake_generictransforms=if!no_mergethenList.maptransforms~f:(Transform.merge_into_generic_mappers~embed_errors~hook~tool_name~expect_mismatch_handler~input_name)else(letget_enclosers~f=List.filter_maptransforms~f:(fun(ct:Transform.t)->matchfctwithNone->None|Somex->Some(ct.name,x))(* Sort them to ensure deterministic ordering *)|>List.sort~cmp:(fun(a,_)(b,_)->String.compareab)|>List.map~f:sndinletrules=List.maptransforms~f:(fun(ct:Transform.t)->ct.rules)|>List.concatandimpl_enclosers=get_enclosers~f:(funct->ct.enclose_impl)andintf_enclosers=get_enclosers~f:(funct->ct.enclose_intf)inmatch(rules,impl_enclosers,intf_enclosers)with|[],[],[]->transforms|_->letmerge_encloser=function|[]->None|enclosers->Some(functxtloc->letheaders,footers=List.mapenclosers~f:(funf->fctxtloc)|>List.splitinletheaders=List.concatheadersinletfooters=List.concat(List.revfooters)in(headers,footers))inTransform.builtin_of_context_free_rewriters~rules~embed_errors~hook~expect_mismatch_handler~enclose_impl:(merge_encloserimpl_enclosers)~enclose_intf:(merge_encloserintf_enclosers)~tool_name~input_name::transforms)|>List.filter~f:(fun(ct:Transform.t)->match(ct.impl,ct.intf)withNone,None->false|_->true)inlinters@preprocess@before_instrs@make_genericcts@after_instrsletapply_transforms~tool_name~file_path~field~lint_field~dropped_so_far~hook~expect_mismatch_handler~input_name~embed_errorsast=letcts=get_whole_ast_passes~tool_name~embed_errors~hook~expect_mismatch_handler~input_nameinletfinish(ast,_dropped,lint_errors,errors)=(ast,List.maplint_errors~f:(fun(loc,s)->Common.attribute_of_warninglocs),errors)inletacc=List.fold_leftcts~init:(ast,[],[],[])~f:(fun(ast,dropped,(lint_errors:_list),errors)(ct:Transform.t)->letinput_name=matchinput_namewith|Someinput_name->input_name|None->"_none_"inletctxt=Expansion_context.Base.top_level~tool_name~file_path~input_nameinletlint_errors,errors=matchlint_fieldctwith|None->(lint_errors,errors)|Somef->(try(lint_errors@fctxtast,errors)withexnwhenembed_errors->(lint_errors,exn_to_loc_errorexn::errors))inmatchfieldctwith|None->(ast,dropped,lint_errors,errors)|Somef->let(ast,more_errors),errors=try(fctxtast,errors)withexnwhenembed_errors->((ast,[]),exn_to_loc_errorexn::errors)inletdropped=if!debug_attribute_dropthen(letnew_dropped=dropped_so_farastindebug_dropped_attributect.name~old_dropped:dropped~new_dropped;new_dropped)else[]in(ast,dropped,lint_errors,errors@more_errors))infinishacc(*$*)leterror_to_str_extensionerror=letloc=Location.noneinletext=Location.Error.to_extensionerrorinAst_builder.Default.pstr_extension~locext[](*$ str_to_sig _last_text_block *)leterror_to_sig_extensionerror=letloc=Location.noneinletext=Location.Error.to_extensionerrorinAst_builder.Default.psig_extension~locext[](*$*)leterror_to_extensionerror~(kind:Kind.t)=matchkindwith|Intf->Intf_or_impl.Intf[error_to_sig_extensionerror]|Impl->Intf_or_impl.Impl[error_to_str_extensionerror]letexn_to_extensionexn~(kind:Kind.t)=exn_to_loc_errorexn|>error_to_extension~kind(* +-----------------------------------------------------------------+
| Actual rewriting of structure/signatures |
+-----------------------------------------------------------------+ *)letprint_passes()=lettool_name="ppxlib_driver"inletembed_errors=falseinlethook=Context_free.Generated_code_hook.nopinletexpect_mismatch_handler=Context_free.Expect_mismatch_handler.nopinletcts=get_whole_ast_passes~embed_errors~hook~expect_mismatch_handler~tool_name~input_name:Noneinif!perform_checksthenPrintf.printf"<builtin:freshen-and-collect-attributes>\n";List.itercts~f:(funct->Printf.printf"%s\n"ct.Transform.name);if!perform_checksthen(Printf.printf"<builtin:check-unused-attributes>\n";if!perform_checks_on_extensionsthenPrintf.printf"<builtin:check-unused-extensions>\n")letsort_errors_by_locerrors=List.sorterrors~cmp:(funerrorerror'->letloc=Location.Error.get_locationerrorinletloc'=Location.Error.get_locationerror'inLocation.comparelocloc')(*$*)letmap_structure_genst~tool_name~hook~expect_mismatch_handler~input_name~embed_errors=Cookies.acknowledge_cookiesT;if!perform_checksthen(Attribute.reset_checks();Attribute.collect#structurest);letlintlint_errorsst=letst=matchlint_errorswith|[]->st|_->List.maplint_errors~f:(fun({attr_name={loc;_};_}asattr)->Ast_builder.Default.pstr_attribute~locattr)@stinstinletwith_errorserrorsst=letsorted=sort_errors_by_locerrorsinList.mapsorted~f:(funerror->Ast_builder.Default.pstr_extension~loc:(Location.Error.get_locationerror)(Location.Error.to_extensionerror)[]|>ghost#structure_item)@stinletcookies_and_checkst=Cookies.call_post_handlersT;leterrors=if!perform_checksthen(* TODO: these two passes could be merged, we now have more passes for
checks than for actual rewriting. *)letunused_attributes_errors=Attribute.collect_unused_attributes_errors#structurest[]inletunused_extension_errors=if!perform_checks_on_extensionsthenExtension.collect_unhandled_extension_errors#structurest[]else[]inletnot_seen_errors=Attribute.collect_unseen_errors()inunused_attributes_errors@unused_extension_errors@not_seen_errorselse[]in(if!perform_locations_checkthenletopenLocation_checkinignore((enforce_invariants!loc_fname)#structurestNon_intersecting_ranges.empty:Non_intersecting_ranges.t));with_errorserrorsstinletfile_path=get_default_path_strstinletst,lint_errors,errors=apply_transformsst~tool_name~file_path~field:(fun(ct:Transform.t)->ct.impl)~lint_field:(fun(ct:Transform.t)->ct.lint_impl)~dropped_so_far:Attribute.dropped_so_far_structure~hook~expect_mismatch_handler~input_name~embed_errorsinst|>lintlint_errors|>cookies_and_check|>with_errors(List.reverrors)|>raise_embedded_errors#structureletmap_structurest=matchmap_structure_genst~tool_name:(Astlib.Ast_metadata.tool_name())~hook:Context_free.Generated_code_hook.nop~expect_mismatch_handler:Context_free.Expect_mismatch_handler.nop~input_name:None~embed_errors:falsewith|ast->ast(*$ str_to_sig _last_text_block *)letmap_signature_gensg~tool_name~hook~expect_mismatch_handler~input_name~embed_errors=Cookies.acknowledge_cookiesT;if!perform_checksthen(Attribute.reset_checks();Attribute.collect#signaturesg);letlintlint_errorssg=letsg=matchlint_errorswith|[]->sg|_->List.maplint_errors~f:(fun({attr_name={loc;_};_}asattr)->Ast_builder.Default.psig_attribute~locattr)@sginsginletwith_errorserrorssg=letsorted=sort_errors_by_locerrorsinList.mapsorted~f:(funerror->Ast_builder.Default.psig_extension~loc:(Location.Error.get_locationerror)(Location.Error.to_extensionerror)[]|>ghost#signature_item)@sginletcookies_and_checksg=Cookies.call_post_handlersT;leterrors=if!perform_checksthen(* TODO: these two passes could be merged, we now have more passes for
checks than for actual rewriting. *)letunused_attributes_errors=Attribute.collect_unused_attributes_errors#signaturesg[]inletunused_extension_errors=if!perform_checks_on_extensionsthenExtension.collect_unhandled_extension_errors#signaturesg[]else[]inletnot_seen_errors=Attribute.collect_unseen_errors()inunused_attributes_errors@unused_extension_errors@not_seen_errorselse[]in(if!perform_locations_checkthenletopenLocation_checkinignore((enforce_invariants!loc_fname)#signaturesgNon_intersecting_ranges.empty:Non_intersecting_ranges.t));with_errorserrorssginletfile_path=get_default_path_sigsginletsg,lint_errors,errors=apply_transformssg~tool_name~file_path~field:(fun(ct:Transform.t)->ct.intf)~lint_field:(fun(ct:Transform.t)->ct.lint_intf)~dropped_so_far:Attribute.dropped_so_far_signature~hook~expect_mismatch_handler~input_name~embed_errorsinsg|>lintlint_errors|>cookies_and_check|>with_errors(List.reverrors)|>raise_embedded_errors#signatureletmap_signaturesg=matchmap_signature_gensg~tool_name:(Astlib.Ast_metadata.tool_name())~hook:Context_free.Generated_code_hook.nop~expect_mismatch_handler:Context_free.Expect_mismatch_handler.nop~input_name:None~embed_errors:falsewith|ast->ast(*$*)(* +-----------------------------------------------------------------+
| Entry points |
+-----------------------------------------------------------------+ *)letstring_contains_binary_asts=lettestmagic_number=String.is_prefixs~prefix:(String.submagic_number~pos:0~len:9)intestAst_magic.ast_intf_magic_number||testAst_magic.ast_impl_magic_numberletversioned_errorfinput_versioninput_file_name=Printf.ksprintf(funmsg->leterr=Location.Error.make~loc:(Location.in_fileinput_file_name)msg~sub:[]inError(err,input_version))letremove_no_errorfn=tryStdlib.Sys.removefnwithSys_error_->()letprotectxx~f~finally=matchfxwith|v->finallyx;v|exceptione->finallyx;raiseeletwith_preprocessed_filefn~f=match!preprocessorwith|None->ffn|Somepp->protectx(Stdlib.Filename.temp_file"ocamlpp""")~finally:remove_no_error~f:(funtmpfile->matchSystem.run_preprocessor~pp~input:fn~output:tmpfilewith|Ok()->ftmpfile|Error(failed_command,fall_back_version)->versioned_errorffall_back_versionfn"Error while running external preprocessor\nCommand line: %s\n"failed_command)letrelocate_mapper=objectinherit[string*string]Ast_traverse.map_with_contextmethod!position(old_fn,new_fn)pos=ifString.equalpos.pos_fnameold_fnthen{poswithpos_fname=new_fn}elseposend(* Set the input name globally. This is used by some ppx rewriters
such as bisect_ppx. *)letset_input_name=Astlib.Location.set_input_nameletload_input~(kind:Kind.t)~input_name~relocatefn=set_input_nameinput_name;letinput_source=ifString.equalfn"-"thenAst_io.StdinelseFilefninletinput_kind=Ast_io.Possibly_source(kind,input_name)inmatchAst_io.readinput_source~input_kindwith|Ok{input_name=ast_input_name;input_version;ast}->letast_kind=Intf_or_impl.kindastinifnot(Kind.equalkindast_kind)thenversioned_errorfinput_versionfn"File contains a binary %s AST but an %s was expected"(Kind.describeast_kind)(Kind.describekind)elseifString.equalast_input_nameinput_name||notrelocatethen(set_input_nameast_input_name;Ok(ast_input_name,input_version,ast))elseOk(input_name,input_version,Intf_or_impl.map_with_contextastrelocate_mapper(ast_input_name,input_name))|Error(Unknown_version(unknown_magic,fall_back_version))->versioned_errorffall_back_versionfn"File is a binary ast for an unknown version of OCaml with magic \
number '%s'"unknown_magic|Error(System_error(error,fall_back_version))|Error(Source_parse_error(error,fall_back_version))->Error(error,fall_back_version)|ErrorNot_a_binary_ast->assertfalseletload_input_run_as_ppxfn=(* If there's an error while loading in run_as_ppx mode, the kind of AST (impl/intf) is still unknown.
That's why, as opposed to load_input, this function raises errors instead of returning a result:
handling an error by returning an AST with the error packed as extension node wouldn't be possible. *)matchAst_io.read(Filefn)~input_kind:Ast_io.Necessarily_binarywith|Ok{input_name=ast_input_name;input_version;ast}->letast=match!loc_fnamewith|None->set_input_nameast_input_name;ast|Someinput_name->set_input_nameinput_name;ifString.equalast_input_nameinput_namethenastelseIntf_or_impl.map_with_contextastrelocate_mapper(ast_input_name,input_name)in(* With `--as-ppx`, ocaml calls the standalone separately for every structure/signature item
with the filename as metadata that it gets from the previous call. relocate_mapper only
relocates positions whose position filename coincides with that metadata filename.
So always return the metadata filename itself, even if `-loc-filename` is provided. *)(ast_input_name,input_version,ast)|Error(Unknown_version(unknown_magic,_))->Location.raise_errorf~loc:(Location.in_filefn)"The input is a binary ast for an unknown version of OCaml with magic \
number '%s'"unknown_magic|ErrorNot_a_binary_ast->Location.raise_errorf~loc:(Location.in_filefn)"Expected a binary AST as input"|Error(System_error(error,_))|Error(Source_parse_error(error,_))->letopenLocation.ErrorinLocation.set_filename(get_locationerror)fn|>update_locerror|>raiseletload_source_filefn=lets=In_channel.read_allfninifstring_contains_binary_aststhenLocation.raise_errorf~loc:(Location.in_filefn)"ppxlib_driver: cannot use -reconcile with binary AST files";stypeoutput_mode=|Pretty_print|Dump_ast|Dparsetree|ReconcileofReconcile.mode|Null(*$*)letextract_cookies_strst=letst=matchstwith|({pstr_desc=Pstr_attribute{attr_name={txt="ocaml.ppx.context";_};_};_;}asprefix)::st->letprefix=Ppxlib_ast.Selected_ast.to_ocamlStructure[prefix]inassert(List.is_empty(Astlib.Ast_metadata.drop_ppx_context_str~restore:trueprefix));st|_->stin(* The cli cookies have to be set after restoring the ppx context,
since restoring the ppx context resets the cookies *)List.iter!Cookies.given_through_cli~f:(fun(name,expr)->Cookies.setTnameexpr);stletadd_cookies_strst=letprefix=Astlib.Ast_metadata.add_ppx_context_str~tool_name:"ppxlib_driver"[]|>Ppxlib_ast.Selected_ast.of_ocamlStructureinprefix@st(*$ str_to_sig _last_text_block *)letextract_cookies_sigsg=letsg=matchsgwith|({psig_desc=Psig_attribute{attr_name={txt="ocaml.ppx.context";_};_};_;}asprefix)::sg->letprefix=Ppxlib_ast.Selected_ast.to_ocamlSignature[prefix]inassert(List.is_empty(Astlib.Ast_metadata.drop_ppx_context_sig~restore:trueprefix));sg|_->sgin(* The cli cookies have to be set after restoring the ppx context,
since restoring the ppx context resets the cookies *)List.iter!Cookies.given_through_cli~f:(fun(name,expr)->Cookies.setTnameexpr);sgletadd_cookies_sigsg=letprefix=Astlib.Ast_metadata.add_ppx_context_sig~tool_name:"ppxlib_driver"[]|>Ppxlib_ast.Selected_ast.of_ocamlSignatureinprefix@sg(*$*)letextract_cookies(ast:Intf_or_impl.t):Intf_or_impl.t=matchastwith|Intfx->Intf(extract_cookies_sigx)|Implx->Impl(extract_cookies_strx)letadd_cookies(ast:Intf_or_impl.t):Intf_or_impl.t=matchastwith|Intfx->Intf(add_cookies_sigx)|Implx->Impl(add_cookies_strx)letcorrections=ref[]letadd_to_listrx=r:=x::!rletregister_correction~loc~repl=add_to_listcorrections(Reconcile.Replacement.make_text()~start:loc.loc_start~stop:loc.loc_end~repl)letprocess_file_hooks=ref[]letregister_process_file_hookf=add_to_listprocess_file_hooksfmoduleFile_property=structtype'at={name:string;mutabledata:'aoption;sexp_of_t:'a->Sexp.t;}typepacked=T:_t->packedletall=ref[]letregistert=add_to_listall(Tt)letreset_all()=List.iter!all~f:(fun(Tt)->t.data<-None)letdump_and_reset_all()=List.filter_map(List.rev!all)~f:(fun(Tt)->matcht.datawith|None->None|Somev->t.data<-None;Some(t.name,t.sexp_of_tv))endmoduleCreate_file_property(Name:sigvalname:stringend)(T:Sexpable.S)=structlett:_File_property.t={name=Name.name;data=None;sexp_of_t=T.sexp_of_t}let()=File_property.registertletsetx=t.data<-Somexendletprocess_ast(ast:Intf_or_impl.t)~input_name~tool_name~hook~expect_mismatch_handler~embed_errors=matchastwith|Intfx->letast=matchmap_signature_genx~tool_name~hook~expect_mismatch_handler~input_name:(Someinput_name)~embed_errorswith|ast->astinIntf_or_impl.Intfast|Implx->letast=matchmap_structure_genx~tool_name~hook~expect_mismatch_handler~input_name:(Someinput_name)~embed_errorswith|ast->astinIntf_or_impl.Implastletprocess_file(kind:Kind.t)fn~input_name~relocate~use_compiler_pprint~output_mode~embed_errors~output=File_property.reset_all();List.iter(List.rev!process_file_hooks)~f:(funf->f());corrections:=[];letreplacements=ref[]inlettool_name="ppx_driver"inlethook:Context_free.Generated_code_hook.t=matchoutput_modewith|Reconcile(Using_line_directives|Delimiting_generated_blocks)->{f=(funcontext(loc:Location.t)generated->add_to_listreplacements(Reconcile.Replacement.make()~context:(Extensioncontext)~start:loc.loc_start~stop:loc.loc_end~repl:generated));}|_->Context_free.Generated_code_hook.nopinletexpect_mismatch_handler:Context_free.Expect_mismatch_handler.t={f=(funcontext(loc:Location.t)generated->add_to_listcorrections(Reconcile.Replacement.make()~context:(Floating_attributecontext)~start:loc.loc_start~stop:loc.loc_end~repl:(Manygenerated)));}inletinput_name,input_version,ast=letpreprocessed_and_loaded=with_preprocessed_filefn~f:(load_input~kind~input_name~relocate)inmatchpreprocessed_and_loadedwith|Ok(input_fname,input_version,ast)->(tryletast=extract_cookiesast|>process_ast~input_name~tool_name~hook~expect_mismatch_handler~embed_errorsin(input_fname,input_version,ast)withexnwhenembed_errors->(input_fname,input_version,exn_to_extensionexn~kind))|Error(error,input_version)whenembed_errors->(input_name,input_version,error_to_extensionerror~kind)|Error(error,_)->letopenLocation.ErrorinLocation.set_filename(get_locationerror)fn|>update_locerror|>raiseinOption.iter!output_metadata_filename~f:(funfn->letmetadata=File_property.dump_and_reset_all()inOut_channel.write_allfn~data:(List.mapmetadata~f:(fun(s,sexp)->Sexp.to_string_hum(Sexp.List[Atoms;sexp])^"\n")|>String.concat~sep:""));letinput_contents=lazy(load_source_filefn)inletcorrected=fn^!corrected_suffixinletmismatches_found=match!correctionswith|[]->ifStdlib.Sys.file_existscorrectedthenStdlib.Sys.removecorrected;false|corrections->Reconcile.reconcilecorrections~contents:(Lazy.forceinput_contents)~output:(Somecorrected)~input_filename:fn~input_name~target:Corrected?styler:!styler~kind~use_compiler_pprint;truein(matchoutput_modewith|Null->()|Pretty_print->with_outputoutput~binary:false~f:(funoc->letppf=Stdlib.Format.formatter_of_out_channelocin(ifuse_compiler_pprintthenUtils.print_as_compiler_sourceppfastelsematchastwith|Intfast->Pprintast.signatureppfast|Implast->Pprintast.structureppfast);letnull_ast=matchastwithIntf[]|Impl[]->true|_->falseinifnotnull_astthenStdlib.Format.pp_print_newlineppf())|Dump_ast->with_outputoutput~binary:true~f:(funoc->Ast_io.writeoc{input_name;input_version;ast}~add_ppx_context:true)|Dparsetree->with_outputoutput~binary:false~f:(funoc->letppf=Stdlib.Format.formatter_of_out_channelocinletast=add_cookiesastin(matchastwith|Intfast->Pp_ast.signatureppfast|Implast->Pp_ast.structureppfast);Stdlib.Format.pp_print_newlineppf())|Reconcilemode->Reconcile.reconcile!replacements~contents:(Lazy.forceinput_contents)~output~input_filename:fn~input_name~target:(Outputmode)?styler:!styler~kind~use_compiler_pprint);ifmismatches_found&&match!diff_commandwithSome"-"->false|_->truethen(Ppxlib_print_diff.print()~file1:fn~file2:corrected~use_color:!use_color?diff_command:!diff_command;Stdlib.exit1)letoutput_mode=refPretty_printletoutput=refNoneletkind=refNoneletinput=refNoneletembed_errors=reffalseletuse_compiler_pprint=reffalseletset_inputfn=match!inputwith|None->input:=Somefn|Some_->raise(Arg.Bad"too many input files")letset_kindk=match!kindwith|Somek'whennot(Kind.equalkk')->raise(Arg.Bad"must specify at most one of -impl or -intf")|_->kind:=Somekletset_output_modemode=match(!output_mode,mode)with|Pretty_print,_->output_mode:=mode|_,Pretty_print->assertfalse|Dump_ast,Dump_ast|Dparsetree,Dparsetree->()|Reconcilea,ReconcilebwhenPoly.equalab->()|x,y->letarg_of_output_mode=function|Pretty_print->assertfalse|Dump_ast->"-dump-ast"|Dparsetree->"-dparsetree"|ReconcileUsing_line_directives->"-reconcile"|ReconcileDelimiting_generated_blocks->"-reconcile-with-comments"|Null->"-null"inraise(Arg.Bad(Printf.sprintf"%s and %s are incompatible"(arg_of_output_modex)(arg_of_output_modey)))letprint_transformations()=List.iter!Transform.all~f:(fun(ct:Transform.t)->Printf.printf"%s\n"ct.name)letparse_apply_lists=letnames=ifString.equals""then[]elseString.split_on_chars~sep:','inList.iternames~f:(funname->ifnot(List.exists!Transform.all~f:(fun(ct:Transform.t)->Transform.has_namectname))thenraise(Stdlib.Arg.Bad(Printf.sprintf"code transformation '%s' does not exist"name)));namestypemask={mutableapply:stringlistoption;mutabledont_apply:stringlistoption;}letmask={apply=None;dont_apply=None}lethandle_applys=ifOption.is_somemask.applythenraise(Arg.Bad"-apply called too many times");(* This is not strictly necessary but it's more intuitive *)ifOption.is_somemask.dont_applythenraise(Arg.Bad"-apply must be called before -dont-apply");mask.apply<-Some(parse_apply_lists)lethandle_dont_applys=ifOption.is_somemask.dont_applythenraise(Arg.Bad"-apply called too many times");mask.dont_apply<-Some(parse_apply_lists)letinterpret_mask()=ifOption.is_somemask.apply||Option.is_somemask.dont_applythenletselected_transform_namect=letis_candidate=matchmask.applywith|None->true|Somenames->List.existsnames~f:(Transform.has_namect)inletis_selected=matchmask.dont_applywith|None->is_candidate|Somenames->is_candidate&¬(List.existsnames~f:(Transform.has_namect))inifis_selectedthenSomect.nameelseNoneinapply_list:=Some(List.filter_map!Transform.all~f:selected_transform_name)letset_cookies=matchString.lsplit2s~on:'='with|None->raise(Arg.Bad"invalid cookie, must be of the form \"<name>=<expr>\"")|Some(name,value)->letlexbuf=Lexing.from_stringvalueinlexbuf.Lexing.lex_curr_p<-{Lexing.pos_fname="<command-line>";pos_lnum=1;pos_bol=0;pos_cnum=0;};letexpr=Parse.expressionlexbufinCookies.given_through_cli:=(name,expr)::!Cookies.given_through_cliletshared_args=[("-loc-filename",Arg.String(funs->loc_fname:=Somes),"<string> File name to use in locations");("-reserve-namespace",Arg.StringName.Reserved_namespaces.reserve,"<string> Mark the given namespace as reserved");("-no-check",Arg.Clearperform_checks," Disable checks (unsafe)");("-check",Arg.Setperform_checks," Enable checks");("-no-check-on-extensions",Arg.Clearperform_checks_on_extensions," Disable checks on extension point only");("-check-on-extensions",Arg.Setperform_checks_on_extensions," Enable checks on extension point only");("-no-locations-check",Arg.Clearperform_locations_check," Disable locations check only");("-locations-check",Arg.Setperform_locations_check," Enable locations check only");("-apply",Arg.Stringhandle_apply,"<names> Apply these transformations in order (comma-separated list)");("-dont-apply",Arg.Stringhandle_dont_apply,"<names> Exclude these transformations");("-no-merge",Arg.Setno_merge," Do not merge context free transformations (better for debugging \
rewriters). As a result, the context-free transformations are not all \
applied before all impl and intf.");("-cookie",Arg.Stringset_cookie,"NAME=EXPR Set the cookie NAME to EXPR");("--cookie",Arg.Stringset_cookie," Same as -cookie");("-raise-embedded-errors",Arg.Setraise_embedded_errors_flag," Raise the first embedded error found in the processed AST");]let()=List.itershared_args~f:(fun(key,spec,doc)->add_argkeyspec~doc)letas_pp()=set_output_modeDump_ast;embed_errors:=trueletstandalone_args=[("-as-ppx",Arg.Unit(fun()->raise(Arg.Bad"-as-ppx must be the first argument"))," Run as a -ppx rewriter (must be the first argument)");("--as-ppx",Arg.Unit(fun()->raise(Arg.Bad"--as-ppx must be the first argument"))," Same as -as-ppx");("-as-pp",Arg.Unitas_pp," Shorthand for: -dump-ast -embed-errors");("--as-pp",Arg.Unitas_pp," Same as -as-pp");("-o",Arg.String(funs->output:=Somes),"<filename> Output file (use '-' for stdout)");("-",Arg.Unit(fun()->set_input"-")," Read input from stdin");("-dump-ast",Arg.Unit(fun()->set_output_modeDump_ast)," Dump the marshaled ast to the output file instead of pretty-printing it");("--dump-ast",Arg.Unit(fun()->set_output_modeDump_ast)," Same as -dump-ast");("-dparsetree",Arg.Unit(fun()->set_output_modeDparsetree)," Print the parsetree (same as ocamlc -dparsetree)");("-embed-errors",Arg.Setembed_errors," Embed errors in the output AST (default: true when -as-pp, false \
otherwise)");("-null",Arg.Unit(fun()->set_output_modeNull)," Produce no output, except for errors");("-impl",Arg.Unit(fun()->set_kindImpl),"<file> Treat the input as a .ml file");("--impl",Arg.Unit(fun()->set_kindImpl),"<file> Same as -impl");("-intf",Arg.Unit(fun()->set_kindIntf),"<file> Treat the input as a .mli file");("--intf",Arg.Unit(fun()->set_kindIntf),"<file> Same as -intf");("-debug-attribute-drop",Arg.Setdebug_attribute_drop," Debug attribute dropping");("-print-transformations",Arg.Setrequest_print_transformations," Print linked-in code transformations, in the order they are applied");("-print-passes",Arg.Setrequest_print_passes," Print the actual passes over the whole AST in the order they are \
applied");("-ite-check",Arg.Unit(fun()->Printf.eprintf"Warning: the -ite-check flag is deprecated and has no effect.\n%!";Extra_warnings.care_about_ite_branch:=true)," (no effect -- kept for compatibility)");("-pp",Arg.String(funs->preprocessor:=Somes),"<command> Pipe sources through preprocessor <command> (incompatible \
with -as-ppx)");("-reconcile",Arg.Unit(fun()->set_output_mode(ReconcileUsing_line_directives))," (WIP) Pretty print the output using a mix of the input source and the \
generated code");("-reconcile-with-comments",Arg.Unit(fun()->set_output_mode(ReconcileDelimiting_generated_blocks))," (WIP) same as -reconcile but uses comments to enclose the generated \
code");("-no-color",Arg.Clearuse_color," Don't use colors when printing errors");("-diff-cmd",Arg.String(funs->diff_command:=Somes)," Diff command when using code expectations (use - to disable diffing)");("-pretty",Arg.Setpretty," Instruct code generators to improve the prettiness of the generated \
code");("-styler",Arg.String(funs->styler:=Somes)," Code styler");("-output-metadata",Arg.String(funs->output_metadata_filename:=Somes),"FILE Where to store the output metadata");("-corrected-suffix",Arg.Set_stringcorrected_suffix,"SUFFIX Suffix to append to corrected files");("-keywords",Arg.String(funs->keywords:=Somes),"<version+list> Set keywords according to the version+list \
specification. Allows using a set of keywords different from the one of \
the current compiler for backward compatibility.");("--keywords",Arg.String(funs->keywords:=Somes),"<version+list> Same as -keywords");("--use-compiler-pp",Arg.Setuse_compiler_pprint,"Force migrating the AST back to the compiler's version before printing \
it as source code using the compiler's Pprintast utilities.");]letget_args?(standalone_args=standalone_args)()=standalone_args@List.rev!argsletstandalone_main()=letusage=Printf.sprintf"%s [extra_args] [<files>]"exe_nameinletargs=get_args()inArg.parse(Arg.alignargs)set_inputusage;Astlib.Keyword.apply_keyword_edition~cli:!keywords();interpret_mask();if!request_print_transformationsthen(print_transformations();Stdlib.exit0);if!request_print_passesthen(print_passes();Stdlib.exit0);match!inputwith|None->Printf.eprintf"%s: no input file given\n%!"exe_name;Stdlib.exit2|Somefn->letkind=match!kindwith|Somek->k|None->(matchKind.of_filenamefnwith|Somek->k|None->Printf.eprintf"%s: don't know what to do with '%s', use -impl or -intf.\n"exe_namefn;Stdlib.exit2)inletinput_name,relocate=match!loc_fnamewithNone->(fn,false)|Somefn->(fn,true)inprocess_filekindfn~input_name~relocate~output_mode:!output_mode~output:!output~embed_errors:!embed_errors~use_compiler_pprint:!use_compiler_pprintletrewrite_binary_ast_fileinput_fnoutput_fn=letinput_name,input_version,ast=load_input_run_as_ppxinput_fninletast=tryletast=extract_cookiesastinlettool_name=Astlib.Ast_metadata.tool_name()inlethook=Context_free.Generated_code_hook.nopinletexpect_mismatch_handler=Context_free.Expect_mismatch_handler.nopinprocess_astast~input_name~tool_name~hook~expect_mismatch_handler~embed_errors:truewithexn->exn_to_extensionexn~kind:(Intf_or_impl.kindast)inwith_output(Someoutput_fn)~binary:true~f:(funoc->Ast_io.writeoc{input_name;input_version;ast}~add_ppx_context:true)letparse_inputpassed_in_args~valid_args~incorrect_input_msg=tryArg.parse_argvpassed_in_args(Arg.alignvalid_args)(fun_->raise(Arg.Bad"anonymous arguments not accepted"))incorrect_input_msgwith|Arg.Badmsg->Printf.eprintf"%s"msg;Stdlib.exit2|Arg.Helpmsg->Printf.eprintf"%s"msg;Stdlib.exit0letrun_as_ppx_rewriter_main~standalone_args~usageinput=letvalid_args=get_args~standalone_args()inmatchList.rev@@Array.to_list@@inputwith|output_fn::input_fn::flags_and_prog_namewhenList.lengthflags_and_prog_name>0->letprog_name_and_flags=List.revflags_and_prog_name|>Array.of_listinparse_inputprog_name_and_flags~valid_args~incorrect_input_msg:usage;interpret_mask();rewrite_binary_ast_fileinput_fnoutput_fn;Stdlib.exit0|[help;_]whenString.equalhelp"-help"||String.equalhelp"--help"->parse_inputinput~valid_args~incorrect_input_msg:usage;assertfalse|_->Printf.eprintf"Usage: %s\n%!"usage;Stdlib.exit2letstandalone_run_as_ppx_rewriter()=letn=Array.lengthStdlib.Sys.argvinletusage=Printf.sprintf"%s -as-ppx [extra_args] <infile> <outfile>"exe_nameinletargv=Array.make(n-1)""inargv.(0)<-Stdlib.Sys.argv.(0);fori=1ton-2doargv.(i)<-Stdlib.Sys.argv.(i+1)done;letstandalone_args=List.mapstandalone_args~f:(fun(arg,spec,_doc)->(arg,spec," Unused with -as-ppx"))inrun_as_ppx_rewriter_main~standalone_args~usageargvletstandalone()=Astlib.init_error_reporting_style_using_env_vars();tryifArray.lengthStdlib.Sys.argv>=2&&matchStdlib.Sys.argv.(1)with|"-as-ppx"|"--as-ppx"->true|_->falsethenstandalone_run_as_ppx_rewriter()elsestandalone_main();Stdlib.exit0withexn->Location.report_exceptionStdlib.Format.err_formatterexn;Stdlib.exit1letrun_as_ppx_rewriter()=letusage=Printf.sprintf"%s [extra_args] <infile> <outfile>"exe_nameinletinput=Stdlib.Sys.argvintryrun_as_ppx_rewriter_main~standalone_args:[]~usageinputwithexn->Location.report_exceptionStdlib.Format.err_formatterexn;Stdlib.exit1letpretty()=!prettyletenable_checks()=(* We do not enable the locations check here, we currently require that one
to be specifically enabled. *)perform_checks:=true;perform_checks_on_extensions:=trueletenable_location_check()=perform_locations_check:=trueletdisable_location_check()=perform_locations_check:=falseletmap_structurest=map_structurestlet()=register_transformation"expand_inline"~rules:[Context_free.Rule.attr_str_floating_expect_and_expand(Attribute.Floating.declare"expand_inline"Structure_itemAst_pattern.(pstr__)Fn.id)(fun~ctxt:_items->Utils.prettify_odoc_attributes#structureitems);Context_free.Rule.attr_sig_floating_expect_and_expand(Attribute.Floating.declare"expand_inline"Signature_itemAst_pattern.(psig__)Fn.id)(fun~ctxt:_items->Utils.prettify_odoc_attributes#signatureitems);]