123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712letmkloc=Location.mklocletmknoloc=Location.mknolocopenPpxlibopenAsttypesopenParsetreeopenAst_helperopenLongidentopenLocation(* Someone above is overriding these ?*)let(=)=Stdlib.(=)let(<>)=Stdlib.(<>)letcache_att=letopenPpxlibinAttribute.(declare"cache"Context.Value_bindingAst_pattern.(pstrnil)())letmerge_att=letopenPpxlibinAttribute.(declare"merge"Context.Value_bindingAst_pattern.(single_expr_payload__)(funx->x))letlayout_att=letopenPpxlibinAttribute.(declare"layout"Context.Value_bindingAst_pattern.(single_expr_payload__)(funx->x))letprint_param_att=letopenPpxlibinAttribute.(declare"print_param"Context.Value_bindingAst_pattern.(single_expr_payload__)(funx->x))letunit_=letloc=nonein[%expr()](* make a location from two *)letmerge_locloc1loc2=ifloc2.loc_ghostthenloc1elseifloc1.loc_ghostthenloc2else{loc1withloc_end=loc2.loc_end}(* an exception to issue a warning when an expression is probably a grammar
but tranformation fails, may be for a syntax error*)exceptionWarnofattributeletwarnlocmsg=raise(Warn(attribute_of_warninglocmsg))letadd_attributeexpatt={expwithpexp_attributes=att::exp.pexp_attributes}(* a mapper to test if an identifier occurs. return true also
if it occuer bounded, this is correct because we only need
that if it returns false then it does not occur *)lethas_identide=letfound=reffalseinletiter=objectinheritAst_traverse.iterassupermethod!expressionexp=matchexp.pexp_descwith|Pexp_ident{txt=Lidentid'}whenid'=id->found:=true;|_->super#expressionexpendinlet_=iter#expressionein!found(* transform an expression in a pattern
- "_" does not work. use "__" instead
- (pat = lid) is the synta for as pattern *)letrecexp_to_patternrmle=letloc=e.pexp_locinmatchewith|{pexp_desc=Pexp_ident({txt=Lidentname;loc=loc_s})}->ifname="__"then(None,false,Pat.any~loc())elseletname=mklocnameloc_sin(Somename,true,Pat.var~locname)|[%expr[%e?e]=[%e?{pexp_desc=Pexp_ident({txt=Lidentname;loc=loc_s})}]]->letname=mklocnameloc_sinlet(_,_,pat)=exp_to_patternrmlein(Somename,true,Pat.aliaspatname)|[%expr([%e?e]:[%t?t])]->let(name,has_id,pat)=exp_to_patternrmlein(name,has_id,[%pat?([%ppat]:[%tt])])|{pexp_desc=Pexp_tuple(l)}->lethas_id,pats=List.fold_left(fun(has_id,pats)(_,hi,pat)->(hi||has_id,pat::pats))(false,[])(List.map(exp_to_patternNone)l)in(None,has_id,Pat.tuple~loc(List.revpats))|[%exprlazy[%e?e]]->(matchrmlwith|None->let(name,has_id,pat)=exp_to_patternNoneein(name,has_id,[%pat?lazy[%ppat]])|Somep->p:=true;exp_to_patternNonee)(* NOTE: the next line works wirh ocaml 4.08.1 and 4.09.0, but not with
4.07.1 ???, best abandon let open in pattern, not so useful *)(*| [%expr let open [%m? { pmod_desc = Pmod_ident m }] in [%e? e]] ->*)(*| { pexp_desc = Pexp_open({popen_expr = { pmod_desc = Pmod_ident m }}, e)} ->
let (name, pat) = exp_to_pattern e in
(name, Pat.open_ ~loc m pat)*)|{pexp_desc=Pexp_construct(c,a)}->(matchawith|None->(None,false,Pat.constructcNone)|Somee->let(_,has_id,pat)=exp_to_patternNoneein(None,has_id,Pat.constructc(Somepat)))|_->warnloc"expression left of \"::\" does not represent a pattern"(* transform an expression into a terminal *)letrecexp_to_termexp=letloc=exp.pexp_locinmatchexpwith|{pexp_desc=Pexp_constant(Pconst_char_)}->[%exprPacomb.Grammar.term(Pacomb.Lex.char[%eexp])]|[%exprCHAR]->[%exprPacomb.Grammar.term(Pacomb.Lex.any())]|[%exprCHAR([%e?s])]->[%exprPacomb.Grammar.term(Pacomb.Lex.char[%es])]|[%exprCHARSET([%e?s])]->[%exprPacomb.Grammar.term(Pacomb.Lex.charset[%es])]|{pexp_desc=Pexp_constant(Pconst_string_)}->[%exprPacomb.Grammar.term(Pacomb.Lex.string[%eexp])]|[%exprSTR([%e?s])]->[%exprPacomb.Grammar.term(Pacomb.Lex.string[%es])]|[%exprUTF8]->[%exprPacomb.Grammar.term(Pacomb.Lex.any_utf8())]|[%exprUTF8([%e?c])]->[%exprPacomb.Grammar.term(Pacomb.Lex.utf8[%ec])]|[%exprGRAPHEME]->[%exprPacomb.Grammar.term(Pacomb.Lex.any_grapheme())]|[%exprGRAPHEME([%e?c])]->[%exprPacomb.Grammar.term(Pacomb.Lex.grapheme[%ec])]|[%exprEOF]->[%exprPacomb.Grammar.term(Pacomb.Lex.eof())]|[%exprRE([%e?s])]->[%exprPacomb.Grammar.term(Pacomb.Regexp.regexp(Pacomb.Regexp.from_string[%es]))]|[%exprNAT]->[%exprPacomb.Grammar.term(Pacomb.Lex.nat())]|[%exprINT]->[%exprPacomb.Grammar.term(Pacomb.Lex.int())]|[%exprFLOAT]->[%exprPacomb.Grammar.term(Pacomb.Lex.float())]|[%exprSTRING_LIT]->[%exprPacomb.Grammar.term(Pacomb.Lex.string_lit())]|[%exprCHAR_LIT]->[%exprPacomb.Grammar.term(Pacomb.Lex.char_lit())]|[%expr~?[[%e?default]][%e?exp]]->[%exprPacomb.Grammar.default_option[%edefault][%eexp_to_termexp]]|[%expr~?[%e?exp]]->[%exprPacomb.Grammar.option[%eexp_to_termexp]]|[%expr~*[[%e?sep]][%e?exp]]->[%exprPacomb.Grammar.star_sep[%eexp_to_termsep][%eexp_to_termexp]]|[%expr~*[%e?exp]]->[%exprPacomb.Grammar.star[%eexp_to_termexp]]|[%expr~+[[%e?sep]][%e?exp]]->[%exprPacomb.Grammar.plus_sep[%eexp_to_termsep][%eexp_to_termexp]]|[%expr~+[%e?exp]]->[%exprPacomb.Grammar.plus[%eexp_to_termexp]]|_->exp(* treat each iterm in a rule. Accept (pat::term) or term when
- pat is an expression accepted by exp_to_pattern
- term is an expression accepted by exp_to_term *)letexp_to_rule_itemis_lazy(e,loc_e)=matchewith|[%expr[%e?epat]::[%e?exp]]->letptr=reffalseinletrml=ifis_lazythenSomeptrelseNoneinlet(name,has_id,pat)=exp_to_patternrmlepatinletexp=exp_to_termexpinletloc=loc_einletexp=if!ptrthen[%exprPacomb.Grammar.force[%eexp]]elseexpin(Some(name,has_id,pat),None,exp,loc_e)|[%expr([%e?dpat],[%e?epat])>:[%e?exp]]->let(name,has_id,pat)=exp_to_patternNoneepatinlet(_,_,dpat)=exp_to_patternNonedpatin(Some(name,has_id,pat),Somedpat,exp_to_termexp,loc_e)|[%expr([%e?epat])<:[%e?exp]]->letloc=exp.pexp_locinletexp=[%exprPacomb.Grammar.appl[%eexp_to_termexp](funx->((),x))]inlet(name,has_id,pat)=exp_to_patternNoneepatinletdpat=Pat.any()in(Some(name,has_id,pat),Somedpat,exp,loc_e)|[%expr(lazy([%e?dpat],[%e?epat]))>:[%e?exp]]->let(name,has_id,pat)=exp_to_patternNoneepatinlet(_,_,dpat)=exp_to_patternNonedpatinletloc=loc_einletexp=[%exprPacomb.Grammar.force[%eexp]]in(Some(name,has_id,pat),Somedpat,exp_to_termexp,loc_e)|_->(None,None,exp_to_terme,loc_e)typecond=CondMatchofexpression*expression|CondTestofexpression|CondNone(* transform exp into rule, that is list of rule item. Accept
- a sequence of items (that is applications of items)
- or () to denote the empty rule *)letrecexp_to_ruleis_lazye=letloc_e=e.pexp_locinmatche.pexp_descwith(* condition with two nested app for an infix *)|Pexp_apply({pexp_desc=Pexp_apply({pexp_desc=Pexp_ident{txt=Lident("="|"<"|">"|"<="|">="|"<>"|"=="|"!="|"<<="|">>="|"==="|"&&"|"||"|"=|"assym)}},[(Nolabel,a0);(Nolabel,a1)])}ascond,(Nolabel,a3)::rest)->let(rule,_)=exp_to_ruleis_lazy(ifrest<>[]thenExp.applya3restelsea3)inletcond=ifsym="=|"thenCondMatch(a0,a1)elseCondTest(cond)in(rule,cond)(* condition with two nested app for not *)|Pexp_apply({pexp_desc=Pexp_apply({pexp_desc=Pexp_ident{txt=Lident("not")}},[(Nolabel,_)])}ascond,(Nolabel,a3)::rest)->let(rule,_)=exp_to_ruleis_lazy(ifrest<>[]thenExp.applya3restelsea3)inletcond=CondTest(cond)in(rule,cond)(* condition with no nested app for an infix *)|Pexp_apply({pexp_desc=Pexp_ident({txt=Lident("="|"<"|">"|"<="|">="|"<>"|"=="|"!="|"<<="|">>="|"==="|"&&"|"||"|"=|"assym0)})}assym,(Nolabel,a0)::(Nolabel,a1)::(Nolabel,a3)::rest)->let(rule,_)=exp_to_ruleis_lazy(ifrest<>[]thenExp.applya3restelsea3)inletcond=ifsym0="=|"thenCondMatch(a0,a1)elseCondTest({ewithpexp_desc=Pexp_apply(sym,(Nolabel,a0)::(Nolabel,a1)::[])})in(rule,cond)(* condition with no nested app for not *)|Pexp_apply({pexp_desc=Pexp_ident({txt=Lident("not")})}assym,(Nolabel,a0)::(Nolabel,a3)::rest)->let(rule,_)=exp_to_ruleis_lazy(ifrest<>[]thenExp.applya3restelsea3)inletcond=CondTest({ewithpexp_desc=Pexp_apply(sym,(Nolabel,a0)::[])})in(rule,cond)|Pexp_construct({txt=Lident"()";loc},None)->([None,None,[%exprPacomb.Grammar.empty()],loc_e],CondNone)|Pexp_apply(e1,args)->lete1,args=matche1,argswith|(([%expr(~*)]|[%expr(~+)]|[%expr(~?)]),((Nolabel,([%expr[__]]asa1))::(Nolabel,a2)::args))->letloc=merge_loce1.pexp_loca2.pexp_locin([%expr[%ee1][%ea1][%ea2]],args)|(([%expr(~*)]|[%expr(~+)]|[%expr(~?)]),(Nolabel,a1)::args)->letloc=merge_loce1.pexp_loca1.pexp_locin([%expr[%ee1][%ea1]],args)|_->(e1,args)inletkn(_,e')=(e',merge_loce'.pexp_locloc_e)inletl=(e1,e.pexp_loc)::List.mapknargsin(List.map(exp_to_rule_itemis_lazy)l,CondNone)|_->([exp_to_rule_itemis_lazy(e,e.pexp_loc)],CondNone)letrecbase_ruleis_lazyacts_fnruleaction=let(rule,cond)=exp_to_ruleis_lazyruleinletloc_a=action.pexp_locinletgl_pos=mknoloc("_pos")inlethas_gl_pos=has_identgl_pos.txtactioninletacts_fn=ifhas_gl_posthen(funexp->letloc=exp.pexp_locin[%exprfun_pos->[%e(acts_fnexp)]])elseacts_fninletgn(acts_fn,rule)(name,dep,item,loc_e)=matchnamewith|None->(acts_fn,(false,false,dep,item,loc_e)::rule)|Some(None,has_id,pat)->letacts_fn=ifhas_idthen(funexp->Exp.fun_~loc:loc_aNolabelNonepat(acts_fnexp))elseacts_fnin(acts_fn,(has_id,false,dep,item,loc_e)::rule)|Some(Someid,has_id,pat)->letid_pos=mkloc(id.txt^"_pos")id.locinlethas_name=has_identid.txtactioninlethas_id_pos=has_identid_pos.txtactioninletpat=ifhas_id_posthenPat.tuple[Pat.varid_pos;pat]elsepatinletacts_fnexp=letloc=exp.pexp_locin(* add ignore(id) if we only use position *)ifnothas_name&&has_id_posthenbeginletid=Exp.ident(mkloc(Lidentid.txt)id.loc)in[%exprfun[%ppat]->ignore[%eid];[%eacts_fnexp]]endelseifnothas_idthenacts_fnexpelse[%exprfun[%ppat]->[%eacts_fnexp]]in(acts_fn,(has_id,has_id_pos,dep,item,loc_e)::rule)inlet(acts_fn,rule)=List.fold_leftgn(acts_fn,[])ruleinletrule=List.revruleinletaction=tryexp_to_grammar~acts_fnactionwith|Exit->letloc=action.pexp_locin[%exprPacomb.Grammar.empty[%eacts_fnaction]]|Warnatt->letloc=action.pexp_locinletexp=[%exprPacomb.Grammar.empty[%eacts_fnaction]]inadd_attributeexpattinletfn(id,pos,dep,item,loc_e)exp=letloc=merge_locloc_eexp.pexp_locinletf=match(id,pos,dep)with|false,false,None->[%exprPacomb.Grammar.iseq]|true,false,None->[%exprPacomb.Grammar.seq]|_,true,None->[%exprPacomb.Grammar.seq_pos]|false,false,Some(_)->[%exprPacomb.Grammar.diseq]|true,false,Some(_)->[%exprPacomb.Grammar.dseq]|_,true,Some(_)->[%exprPacomb.Grammar.dseq_pos]inletexp=matchdep,id,poswith|None,_,_->exp|Somepat,false,false->[%exprfun([%ppat],())->[%eexp]]|Somepat,_,_->[%exprfun[%ppat]->[%eexp]]in[%expr[%ef][%eitem][%eexp]]inletrule=List.fold_rightfnruleactioninletrule=ifhas_gl_posthenletloc=rule.pexp_locin[%exprPacomb.Grammar.mk_pos[%erule]]elseruleinmatchcondwith|CondNone->rule|CondTest(cond)->letloc=rule.pexp_locin[%exprif[%econd]then[%erule]elsePacomb.Grammar.fail()]|CondMatch(a0,a1)->let(_,_,pat)=exp_to_patternNonea1inletloc=rule.pexp_locin[%exprmatch[%ea0]with[%ppat]->[%erule]|_->Pacomb.Grammar.fail()](* transform an expression into a list of rules with action
- name_param is an optional arguments for an eventual parameter name
- fn is a function to modify the action. It adds [Exp.fun _] conctructs *)andexp_to_rules?name_param?(acts_fn=(funexp->exp))e=matchewith(* base case [items => action] *)|[%expr[%e?rule]=>lazy[%e?action]]->letrule=base_ruletrueacts_fnruleactioninletloc=e.pexp_locin[[%exprPacomb.Grammar.lazy_[%erule]]]|[%expr[%e?rule]=>[%e?action]]->[base_rulefalseacts_fnruleaction](* inheritance case [prio1 < prio2 < ... < prion] *)|[%expr[%e?_]<[%e?_]]whenname_param<>None->letrecfnexp=matchexpwith|[%expr[%e?x]<[%e?y]]->y::fnx|_->[exp]inletprios=fneinlet(name,param,_,_)=matchname_paramwithNone->assertfalse|Somex->xinletparam=mknoloc(Lidentparam)inletloc=e.pexp_locinletrecgnaccl=matchlwith|x::(y::_asl)->lete=[%exprif[%eExp.identparam]=[%ex]then[%eExp.identname][%ey]elsePacomb.Grammar.fail()]ingn(e::acc)l|[]|[_]->accingn[]prios|[%exprERROR([%e?{pexp_desc=Pexp_constant(Pconst_string_)}ass])]->letloc=e.pexp_locin[[%exprPacomb.Grammar.error[[%es]]]]|[%exprERROR([%e?s])]->letloc=e.pexp_locin[[%exprPacomb.Grammar.error[%es]]](* alternatives represented as sequence *)|[%expr[%e?e1];[%e?e2]]->exp_to_rules?name_param~acts_fne1@exp_to_rules?name_param~acts_fne2(* not a grammar at all (no warning)! *)|_->raiseExit(* transform an expression into grammar, by adding [alt] combinators
to the result of exp_to_rules *)andexp_to_grammar?name_param?(acts_fn=(funexp->exp))exp=letrules=exp_to_rules?name_param~acts_fnexpinletloc=exp.pexp_locinmatchruleswith(* three cases for better location ? *)|[]->[%exprPacomb.Grammar.fail()]|[x]->x|_->letrecfn=function|[]->[%expr[]]|x::l->letexp=fnlinletloc=merge_locx.pexp_locexp.pexp_locin[%expr[%ex]::[%eexp]]inletexp=fnrulesin[%exprPacomb.Grammar.alt[%eexp]](* remove acts_fn argument and handle exceptions *)letexp_to_grammar?name_paramexp=try(true,exp_to_grammar?name_paramexp)withExit->(false,exp)|Warnatt->(false,add_attributeexpatt)(* transform a list of structure_items in one *)letflatten_stritems=matchitemswith|[x]->x|_->Str.include_{pincl_mod=Mod.structureitems;pincl_loc=Location.none;pincl_attributes=[]}letgen_id=letc=ref0in(funs->incrc;s^(string_of_int!c))letvb_to_parserrec_vb=letgnvb=letloc=vb.pvb_locinletrectreat_patp=matchp.ppat_descwith|Ppat_vars->(s,false)|Ppat_alias(_,s)->(s,false)|Ppat_open(_,p)->treat_patp|Ppat_constraint(p,_)->treat_patp|_->(mknoloc"",true)inlet(name,do_warn)=treat_patvb.pvb_patinlet(params,exp)=letrecfnexp=matchexp.pexp_descwith|Pexp_fun(lbl,def,param,exp)whenrec_=Recursive->let(params,exp)=fnexpin((lbl,def,param)::params,exp)|_->([],exp)infnvb.pvb_exprinlet(name,param)=matchparamswith[]->(name,None)|[(Nolabel,None,p)]->(name,Some(p,None))|ps->letcurry=List.map(fun(lbl,def,_)->(lbl,def))psinletps=List.map(fun(_,_,p)->p)psin(mkloc(name.txt^"@uncurry")name.loc,Some(Pat.tuple~loc:vb.pvb_expr.pexp_loc(ps),Somecurry))inletname_param=matchparamwith|None->None|Some(p,curry)->Some(mkloc(Lidentname.txt)name.loc,gen_id"@p",p,curry)inlet(changed,rules)=exp_to_grammar?name_paramexpinifchanged&&do_warnthenwarnvb.pvb_pat.ppat_loc"Pattern not allowed here for grammar parameter";letrules=matchPpxlib.Attribute.getlayout_attvbwith|Some[%expr[%e?blank]~config:[%e?config]]->[%exprPacomb.Grammar.layout~config:[%econfig][%eblank][%erules]]|Some[%expr[%e?blank]]->[%exprPacomb.Grammar.layout[%eblank][%erules]]|None->rulesinletrules=matchPpxlib.Attribute.getmerge_attvbwith|Somee->[%exprPacomb.Grammar.cache~merge:[%ee][%erules]]|None->rulesinletrules=matchPpxlib.Attribute.getcache_attvbwith|Some_->[%exprPacomb.Grammar.cache[%erules]]|None->rulesinletrules=ifrec_=Nonrecursive&&changedthen[%exprPacomb.Grammar.give_name[%eExp.constant~loc:name.loc(Const.stringname.txt)][%erules]]elserulesin(loc,changed,name,vb,name_param,rules)inletls=List.mapgnvbinifnot(List.exists(fun(_,changed,_,_,_,_)->changed)ls)thenraiseExit;let(gr,orig)=List.partition(fun(_,changed,_,_,_,_)->changed&&rec_=Recursive)lsinletsetname="set__grammar__"^name.txtinletdeclarations=letgn(loc,changed,(name:stringloc),vb,param,_)=assertchanged;matchparamwith|None->letexpr=[%exprPacomb.Grammar.declare_grammar[%eExp.constant~loc:name.loc(Const.stringname.txt)]]inletexpr=matchPpxlib.Attribute.getprint_param_attvbwith|Some_->add_attributeexpr(attribute_of_warningloc"useless @print_param attribute")|None->exprin[Vb.mk~locvb.pvb_patexpr]|Some(_,_,_,curry)->letpat=ifcurry<>NonethenPat.varnameelsevb.pvb_patinletgname=Exp.constant~loc:name.loc(Const.stringname.txt)inletexpr=matchPpxlib.Attribute.getprint_param_attvbwith|Somepr->[%exprPacomb.Grammar.grammar_family~param_to_string:[%epr][%egname]]|None->[%exprPacomb.Grammar.grammar_family[%egname]]in[Vb.mk~loc(Pat.tuple[pat;Pat.var(mkloc(setname)name.loc)])expr]inlethn(loc,_,(name:stringloc),vb,param,_)=matchparamwith|Some(_,_,_,Somelbls)->letargs=List.mapi(funi(lbl,def)->(lbl,def,mknoloc("x@"^string_of_inti)))lblsinlettuple=Exp.tuple(List.map(fun(_,_,v)->Exp.ident(mknoloc(Lidentv.txt)))args)inletexp=[%expr[%eExp.ident(mkloc(Lidentname.txt)name.loc)][%etuple]]inletexp=List.fold_right(fun(lbl,def,v)exp->letpat=Pat.varvinExp.fun_lbldefpatexp)argsexpin[Vb.mk~locvb.pvb_patexp]|_->[]inList.mapgngr@List.maphngrinletorig=letgn(_,_,_,vb,_,_)=vbinList.mapgnoriginletdefinitions=letfn(loc,changed,name,_,param,rules)=assertchanged;letexp=matchparamwith|None->[%exprPacomb.Grammar.set_grammar[%eExp.ident(mkloc(Lidentname.txt)name.loc)][%erules]]|Some(_,pn,pat,_)->letpat=Pat.aliaspat(mknolocpn)in[%expr[%eExp.ident(mkloc(Lident(setname))name.loc)](fun[%ppat]->[%erules])]in[Vb.mk~loc(Pat.any())exp]inList.mapfngrin(declarations,orig,definitions)(* transform a list of structure item to parser definition *)letstr_to_parseritems=letfnitem=trymatchitem.pstr_descwith|Pstr_value(rec_,ls)->letdeclarations,orig,definitions=vb_to_parserrec_lsinletfnls=List.fold_right(funxa->ifx=[]thenaelseStr.valueNonrecursivex::a)ls[]infndeclarations@(iforig=[]then[]else[Str.valuerec_orig])@fndefinitions|_->[item]withWarnw->(* NOTE: there is no place for attribute in structure_item:
add an include for that! *)[Str.include_{pincl_mod=Mod.structureitems;pincl_loc=Location.none;pincl_attributes=[w]}]|Exit->itemsinflatten_str(List.flatten(List.mapfnitems))letexp_to_parsere=trymatche.pexp_descwith|Pexp_let(rec_,vb,e0)->letdeclarations,orig,definitions=vb_to_parserrec_vbinletfnlse0=List.fold_right(funvbe->ifvb=[]theneelseExp.let_Nonrecursivevbe)lse0inletdefs=(fndefinitionse0)infndeclarations(iforig=[]thendefselseExp.let_rec_origdefs)|_->snd(exp_to_grammare)withExit->e|Warnatt->add_attributeeattopenPpxlibmoduleAst=Ast_builder.Defaultletexpand_expressionexpr=exp_to_parserexprletmap_all=objectinheritAst_traverse.mapassupermethod!expressione=super#expression(exp_to_parsere)method!structure_item=(funi->super#structure_item(str_to_parser[i]))endletrule_expr=letctx=Extension.Context.expressioninletpat=Ast_pattern.(single_expr_payload__)inletext=Extension.declare"parser"ctxpat(fun~loc:_~path:_->map_all#expression)inContext_free.Rule.extensionextletrule_str_item=letctx=Extension.Context.structure_iteminletpat=Ast_pattern.(pstr__)inletext=Extension.declare"parser"ctxpat(fun~loc:_~path:_l->(flatten_str(List.mapmap_all#structure_iteml)))inContext_free.Rule.extensionextlet_=letrules=[rule_expr;rule_str_item]inDriver.register_transformation~rules"ppx_pacomb"