1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546(*$ open Ppxlib_cinaps_helpers $*)openImportopenUtilsopenCommonopenWith_errorsmoduleArg=Caml.Argletexe_name=Caml.Filename.basenameCaml.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"letghost=objectinheritAst_traverse.mapmethod!locationloc={locwithloc_ghost=true}endmoduleLint_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:[Caml.__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~hook~expect_mismatch_handler~tool_name~input_name=let{rules;enclose_impl;enclose_intf;impl;intf;_}=tinletmap=newContext_free.map_top_downrules~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=File_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=File_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}->Caml.Format.eprintf"- %a: %s\n"Location.printloctxt);Caml.Format.eprintf"@.")inprint_diff"disappeared"new_droppedold_dropped;print_diff"reappeared"old_droppednew_droppedletget_whole_ast_passes~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~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~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(typet)~tool_name~file_path~field~lint_field~dropped_so_far~hook~expect_mismatch_handler~input_name~f_exception~embed_errorsx=letexceptionWrapperoftlist*labelloclist*(location*label)list*exn*Location.Error.tlistinletcts=get_whole_ast_passes~tool_name~hook~expect_mismatch_handler~input_nameinletfinish(x,_dropped,lint_errors,errors)=(x,List.maplint_errors~f:(fun(loc,s)->Common.attribute_of_warninglocs),errors)intryletacc=List.fold_leftcts~init:(x,[],[],[])~f:(fun(x,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=matchlint_fieldctwith|None->lint_errors|Somef->(trylint_errors@fctxtxwithexnwhenembed_errors->raise@@Wrapper(x,dropped,lint_errors,exn,errors))inmatchfieldctwith|None->(x,dropped,lint_errors,errors)|Somef->letx,more_errors=tryfctxtxwithexnwhenembed_errors->raise@@Wrapper(x,dropped,lint_errors,exn,errors)inletdropped=if!debug_attribute_dropthen(letnew_dropped=dropped_so_farxindebug_dropped_attributect.name~old_dropped:dropped~new_dropped;new_dropped)else[]in(x,dropped,lint_errors,errors@more_errors))inOk(finishacc)withWrapper(x,dropped,lint_errors,exn,errors)->Error(finish(f_exceptionexn::x,dropped,lint_errors,errors))(*$*)leterror_to_str_extensionerror=letloc=Location.noneinletext=Location.Error.to_extensionerrorinAst_builder.Default.pstr_extension~locext[]letexn_to_str_extensionexn=matchLocation.Error.of_exnexnwith|None->raiseexn|Someerror->error_to_str_extensionerror(*$ str_to_sig _last_text_block *)leterror_to_sig_extensionerror=letloc=Location.noneinletext=Location.Error.to_extensionerrorinAst_builder.Default.psig_extension~locext[]letexn_to_sig_extensionexn=matchLocation.Error.of_exnexnwith|None->raiseexn|Someerror->error_to_sig_extensionerror(*$*)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)=matchLocation.Error.of_exnexnwith|None->raiseexn|Someerror->error_to_extensionerror~kind(* +-----------------------------------------------------------------+
| Actual rewriting of structure/signatures |
+-----------------------------------------------------------------+ *)letprint_passes()=lettool_name="ppxlib_driver"inlethook=Context_free.Generated_code_hook.nopinletexpect_mismatch_handler=Context_free.Expect_mismatch_handler.nopinletcts=get_whole_ast_passes~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")(*$*)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=List.maperrors~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()in(if!perform_locations_checkthenletopenLocation_checkinignore((enforce_invariants!loc_fname)#structurestNon_intersecting_ranges.empty:Non_intersecting_ranges.t));unused_attributes_errors@unused_extension_errors@not_seen_errors)else[]inwith_errorserrorsstinletfile_path=File_path.get_default_path_strstinmatchapply_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~f_exception:(funexn->exn_to_str_extensionexn)~embed_errorswith|Error(st,lint_errors,errors)->Error(st|>lintlint_errors|>with_errorserrors)|Ok(st,lint_errors,errors)->Ok(st|>lintlint_errors|>cookies_and_check|>with_errorserrors)letmap_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|Okast|Errorast->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=List.maperrors~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()in(if!perform_locations_checkthenletopenLocation_checkinignore((enforce_invariants!loc_fname)#signaturesgNon_intersecting_ranges.empty:Non_intersecting_ranges.t));unused_attributes_errors@unused_extension_errors@not_seen_errors)else[]inwith_errorserrorssginletfile_path=File_path.get_default_path_sigsginmatchapply_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~f_exception:(funexn->exn_to_sig_extensionexn)~embed_errorswith|Error(sg,lint_errors,errors)->Error(sg|>lintlint_errors|>with_errorserrors)|Ok(sg,lint_errors,errors)->Ok(sg|>lintlint_errors|>cookies_and_check|>with_errorserrors)letmap_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|Okast|Errorast->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=tryCaml.Sys.removefnwithSys_error_->()letprotectxx~f~finally=matchfxwith|v->finallyx;v|exceptione->finallyx;raiseeletwith_preprocessed_filefn~f=match!preprocessorwith|None->ffn|Somepp->protectx(Caml.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|Errorast|Okast->astinIntf_or_impl.Intfast|Implx->letast=matchmap_structure_genx~tool_name~hook~expect_mismatch_handler~input_name:(Someinput_name)~embed_errorswith|Errorast|Okast->astinIntf_or_impl.Implastletprocess_file(kind:Kind.t)fn~input_name~relocate~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|[]->ifCaml.Sys.file_existscorrectedthenCaml.Sys.removecorrected;false|corrections->Reconcile.reconcilecorrections~contents:(Lazy.forceinput_contents)~output:(Somecorrected)~input_filename:fn~input_name~target:Corrected?styler:!styler~kind;truein(matchoutput_modewith|Null->()|Pretty_print->with_outputoutput~binary:false~f:(funoc->letppf=Caml.Format.formatter_of_out_channelocin(matchastwith|Intfast->Pprintast.signatureppfast|Implast->Pprintast.structureppfast);letnull_ast=matchastwithIntf[]|Impl[]->true|_->falseinifnotnull_astthenCaml.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=Caml.Format.formatter_of_out_channelocinletast=add_cookiesastin(matchastwith|Intfast->Sexp.pp_humppf(Ast_traverse.sexp_of#signatureast)|Implast->Sexp.pp_humppf(Ast_traverse.sexp_of#structureast));Caml.Format.pp_print_newlineppf())|Reconcilemode->Reconcile.reconcile!replacements~contents:(Lazy.forceinput_contents)~output~input_filename:fn~input_name~target:(Outputmode)?styler:!styler~kind);ifmismatches_found&&match!diff_commandwithSome"-"->false|_->truethen(Ppxlib_print_diff.print()~file1:fn~file2:corrected~use_color:!use_color?diff_command:!diff_command;Caml.exit1)letoutput_mode=refPretty_printletoutput=refNoneletkind=refNoneletinput=refNoneletembed_errors=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(Caml.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");]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 -dump-ast, 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");]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;interpret_mask();if!request_print_transformationsthen(print_transformations();Caml.exit0);if!request_print_passesthen(print_passes();Caml.exit0);match!inputwith|None->Printf.eprintf"%s: no input file given\n%!"exe_name;Caml.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;Caml.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_errorsletrewrite_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;Caml.exit2|Arg.Helpmsg->Printf.eprintf"%s"msg;Caml.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;Caml.exit0|[help;_]whenString.equalhelp"-help"||String.equalhelp"--help"->parse_inputinput~valid_args~incorrect_input_msg:usage;assertfalse|_->Printf.eprintf"Usage: %s\n%!"usage;Caml.exit2letstandalone_run_as_ppx_rewriter()=letn=Array.lengthCaml.Sys.argvinletusage=Printf.sprintf"%s -as-ppx [extra_args] <infile> <outfile>"exe_nameinletargv=Array.make(n-1)""inargv.(0)<-Caml.Sys.argv.(0);fori=1ton-2doargv.(i)<-Caml.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.lengthCaml.Sys.argv>=2&&matchCaml.Sys.argv.(1)with"-as-ppx"|"--as-ppx"->true|_->falsethenstandalone_run_as_ppx_rewriter()elsestandalone_main();Caml.exit0withexn->Location.report_exceptionCaml.Format.err_formatterexn;Caml.exit1letrun_as_ppx_rewriter()=letusage=Printf.sprintf"%s [extra_args] <infile> <outfile>"exe_nameinletinput=Caml.Sys.argvintryrun_as_ppx_rewriter_main~standalone_args:[]~usageinputwithexn->Location.report_exceptionCaml.Format.err_formatterexn;Caml.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_structurest