123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920open!StdunemoduleAtom=AtommoduleTemplate=TemplatemoduleSyntax=Syntaxtypesyntax=Syntax.t=Jbuild|Dunetypet=|AtomofAtom.t|Quoted_stringofstring|Listoftlist|TemplateofTemplate.tletatom_or_quoted_strings=ifAtom.is_valid_dunesthenAtom(Atom.of_strings)elseQuoted_stringsletatoms=Atom(Atom.of_strings)letunsafe_atom_of_strings=atomsletrecto_stringt~syntax=matchtwith|Atoma->Atom.printasyntax|Quoted_strings->Escape.quoteds~syntax|Listl->Printf.sprintf"(%s)"(List.mapl~f:(to_string~syntax)|>String.concat~sep:" ")|Templatet->Template.to_stringt~syntaxletrecppsyntaxppf=function|Atoms->Format.pp_print_stringppf(Atom.printssyntax)|Quoted_strings->Format.pp_print_stringppf(Escape.quoted~syntaxs)|List[]->Format.pp_print_stringppf"()"|List(first::rest)->Format.pp_open_boxppf1;Format.pp_print_stringppf"(";Format.pp_open_hvboxppf0;ppsyntaxppffirst;List.iterrest~f:(funsexp->Format.pp_print_spaceppf();ppsyntaxppfsexp);Format.pp_close_boxppf();Format.pp_print_stringppf")";Format.pp_close_boxppf()|Templatet->Template.ppsyntaxppftletpp_quoted=letrecloop=function|Atom(As)ast->ifAtom.is_valid_dunesthentelseQuoted_strings|Listxs->List(List.map~f:loopxs)|(Quoted_string_|Template_)ast->tinfunppft->ppDuneppf(loopt)letpp_print_quoted_stringppfs=letsyntax=DuneinifString.containss'\n'thenbeginmatchString.splits~on:'\n'with|[]->Format.pp_print_stringppf(Escape.quoted~syntaxs)|first::rest->Format.fprintfppf"@[<hv 1>\"@{<atom>%s"(Escape.escaped~syntaxfirst);List.iterrest~f:(funs->Format.fprintfppf"@,\\n%s"(Escape.escaped~syntaxs));Format.fprintfppf"@}\"@]"endelseFormat.pp_print_stringppf(Escape.quoted~syntaxs)letrecpp_split_stringsppf=function|Atoms->Format.pp_print_stringppf(Atom.printsSyntax.Dune)|Quoted_strings->pp_print_quoted_stringppfs|List[]->Format.pp_print_stringppf"()"|List(first::rest)->Format.pp_open_boxppf1;Format.pp_print_stringppf"(";Format.pp_open_hvboxppf0;pp_split_stringsppffirst;List.iterrest~f:(funsexp->Format.pp_print_spaceppf();pp_split_stringsppfsexp);Format.pp_close_boxppf();Format.pp_print_stringppf")";Format.pp_close_boxppf()|Templatet->Template.pp_split_stringsppfttypeformatter_state=|In_atom|In_makefile_action|In_makefile_stuffletprepare_formatterppf=letstate=ref[]inFormat.pp_set_mark_tagsppftrue;letofuncs=Format.pp_get_formatter_out_functionsppf()inlettfuncs=Format.pp_get_formatter_tag_functionsppf()inFormat.pp_set_formatter_tag_functionsppf{tfuncswithmark_open_tag=(function|"atom"->state:=In_atom::!state;""|"makefile-action"->state:=In_makefile_action::!state;""|"makefile-stuff"->state:=In_makefile_stuff::!state;""|s->tfuncs.mark_open_tags);mark_close_tag=(function|"atom"|"makefile-action"|"makefile-stuff"->state:=List.tl!state;""|s->tfuncs.mark_close_tags)};Format.pp_set_formatter_out_functionsppf{ofuncswithout_newline=(fun()->match!statewith|[In_atom;In_makefile_action]->ofuncs.out_string"\\\n\t"03|[In_atom]->ofuncs.out_string"\\\n"02|[In_makefile_action]->ofuncs.out_string" \\\n\t"04|[In_makefile_stuff]->ofuncs.out_string" \\\n"03|[]->ofuncs.out_string"\n"01|_->assertfalse);out_spaces=(funn->ofuncs.out_spaces(match!statewith|In_atom::_->max0(n-2)|_->n))}moduleAst=structtypedune_lang=ttypet=|AtomofLoc.t*Atom.t|Quoted_stringofLoc.t*string|TemplateofTemplate.t|ListofLoc.t*tlistletatom_or_quoted_stringlocs=matchatom_or_quoted_stringswith|Atoma->Atom(loc,a)|Quoted_strings->Quoted_string(loc,s)|Template_|List_->assertfalseletloc(Atom(loc,_)|Quoted_string(loc,_)|List(loc,_)|Template{loc;_})=locletrecremove_locst:dune_lang=matchtwith|Templatet->Template(Template.remove_locst)|Atom(_,s)->Atoms|Quoted_string(_,s)->Quoted_strings|List(_,l)->List(List.mapl~f:remove_locs)endletrecadd_loct~loc:Ast.t=matchtwith|Atoms->Atom(loc,s)|Quoted_strings->Quoted_string(loc,s)|Listl->List(loc,List.mapl~f:(add_loc~loc))|Templatet->Template{twithloc}moduleParse_error=structincludeLexer.Errorletloct:Loc.t={start=t.start;stop=t.stop}letmessaget=t.messageendexceptionParse_error=Lexer.ErrormoduleLexer=LexermoduleParser=structleterror(loc:Loc.t)message=raise(Parse_error{start=loc.start;stop=loc.stop;message})moduleMode=structtype'at=|Single:Ast.tt|Many:Ast.tlistt|Many_as_one:Ast.ttletmake_result:typea.at->Lexing.lexbuf->Ast.tlist->a=funtlexbufsexps->matchtwith|Single->beginmatchsexpswith|[sexp]->sexp|[]->error(Loc.of_lexbuflexbuf)"no s-expression found in input"|_::sexp::_->error(Ast.locsexp)"too many s-expressions found in input"end|Many->sexps|Many_as_one->matchsexpswith|[]->List(Loc.in_filelexbuf.lex_curr_p.pos_fname,[])|x::l->letlast=List.fold_leftl~init:x~f:(fun_x->x)inletloc={(Ast.locx)withstop=(Ast.loclast).stop}inList(loc,x::l)endletrecloopdepthlexerlexbufacc=match(lexerlexbuf:Lexer.Token.t)with|Atoma->letloc=Loc.of_lexbuflexbufinloopdepthlexerlexbuf(Ast.Atom(loc,a)::acc)|Quoted_strings->letloc=Loc.of_lexbuflexbufinloopdepthlexerlexbuf(Quoted_string(loc,s)::acc)|Templatet->letloc=Loc.of_lexbuflexbufinloopdepthlexerlexbuf(Template{twithloc}::acc)|Lparen->letstart=Lexing.lexeme_start_plexbufinletsexps=loop(depth+1)lexerlexbuf[]inletstop=Lexing.lexeme_end_plexbufinloopdepthlexerlexbuf(List({start;stop},sexps)::acc)|Rparen->ifdepth=0thenerror(Loc.of_lexbuflexbuf)"right parenthesis without matching left parenthesis";List.revacc|Sexp_comment->letsexps=letloc=Loc.of_lexbuflexbufinmatchloopdepthlexerlexbuf[]with|_::sexps->sexps|[]->errorloc"s-expression missing after #;"inList.rev_appendaccsexps|Eof->ifdepth>0thenerror(Loc.of_lexbuflexbuf)"unclosed parenthesis at end of input";List.revaccletparse~mode?(lexer=Lexer.token)lexbuf=loop0lexerlexbuf[]|>Mode.make_resultmodelexbufendletparse_string~fname~mode?lexerstr=letlb=Lexing.from_stringstrinlb.lex_curr_p<-{pos_fname=fname;pos_lnum=1;pos_bol=0;pos_cnum=0};Parser.parse~mode?lexerlbtypedune_lang=tmoduleEncoder=structtypenonrec'at='a->tletunit()=List[]letstring=atom_or_quoted_stringletintn=Atom(Atom.of_intn)letfloatf=Atom(Atom.of_floatf)letboolb=Atom(Atom.of_boolb)letpairfafb(a,b)=List[faa;fbb]lettriplefafbfc(a,b,c)=List[faa;fbb;fcc]letlistfl=List(List.mapl~f)letarrayfa=listf(Array.to_lista)letoptionf=function|None->List[]|Somex->List[fx]letrecordl=List(List.mapl~f:(fun(n,v)->List[Atom(Atom.of_stringn);v]))typefield=|Absent|Normalofstring*dune_lang|Inlined_listofstring*dune_langlistletfieldnamef?(equal=(=))?defaultv=matchdefaultwith|None->Normal(name,fv)|Somed->ifequaldvthenAbsentelseNormal(name,fv)letfield_onamefv=matchvwith|None->Absent|Somev->Normal(name,fv)letfield_lnamefl=matchlwith|[]->Absent|_->Inlined_list(name,List.mapl~f)letrecord_fields(syntax:Syntax.t)(l:fieldlist)=List.filter_mapl~f:(function|Absent->None|Normal(name,v)->Some(List[Atom(Atom.of_stringname);v])|Inlined_list(name,l)->Some(List(Atom(Atom.of_stringname)::matchsyntaxwith|Dune->l|Jbuild->[Listl])))letunknown_=unsafe_atom_of_string"<unknown>"endmoduleDecoder=structtypeast=Ast.t=|AtomofLoc.t*Atom.t|Quoted_stringofLoc.t*string|TemplateofTemplate.t|ListofLoc.t*astlisttypehint={on:string;candidates:stringlist}exceptionDecoderofLoc.t*string*hintoptionletof_sexp_error?hintlocmsg=raise(Decoder(loc,msg,hint))letof_sexp_errorf?hintlocfmt=Printf.ksprintf(funmsg->of_sexp_errorloc?hintmsg)fmtletno_templates?hintlocfmt=Printf.ksprintf(funmsg->of_sexp_errorloc?hint("No variables allowed "^msg))fmtmoduleName=structmoduleT=structtypet=stringletcompareab=letalen=String.lengthaandblen=String.lengthbinmatchInt.comparealenblenwith|Eq->String.compareab|ne->neendincludeTmoduleMap=Map.Make(T)endmoduleFields=structmoduleUnparsed=structtypet={values:Ast.tlist;entry:Ast.t;prev:toption(* Previous occurrence of this field *)}endtypet={unparsed:Unparsed.tName.Map.t;known:stringlist}letconsumenamestate={unparsed=Name.Map.removestate.unparsedname;known=name::state.known}letadd_knownnamestate={statewithknown=name::state.known}letunparsed_ast{unparsed;_}=letrecloopacc=function|[]->acc|x::xs->beginmatchx.Unparsed.prevwith|None->loop(x.entry::acc)xs|Somep->loop(x.entry::acc)(p::xs)endinloop[](Name.Map.valuesunparsed)|>List.sort~compare:(funab->Int.compare(Ast.loca).start.pos_cnum(Ast.locb).start.pos_cnum)endtypefields=Fields.ttypevalues=Ast.tlist(* Arguments are:
- the location of the whole list
- the first atom when parsing a constructor or a field
- the universal map holding the user context
*)type'kindcontext=|Values:Loc.t*stringoption*Univ_map.t->valuescontext|Fields:Loc.t*stringoption*Univ_map.t->Fields.tcontexttype('a,'kind)parser='kindcontext->'kind->'a*'kindtype'at=('a,values)parsertype'afields_parser=('a,Fields.t)parserletreturnx_ctxstate=(x,state)let(>>=)tfctxstate=letx,state=tctxstateinfxctxstatelet(>>|)tfctxstate=letx,state=tctxstatein(fx,state)let(>>>)abctxstate=let(),state=actxstateinbctxstateletmapt~f=t>>|flettry_tfctxstate=trytctxstatewithexn->fexnctxstateletget_user_context:typek.kcontext->Univ_map.t=function|Values(_,_,uc)->uc|Fields(_,_,uc)->ucletgetkeyctxstate=(Univ_map.find(get_user_contextctx)key,state)letget_allctxstate=(get_user_contextctx,state)letset:typeabk.aUniv_map.Key.t->a->(b,k)parser->(b,k)parser=funkeyvtctxstate->matchctxwith|Values(loc,cstr,uc)->t(Values(loc,cstr,Univ_map.adduckeyv))state|Fields(loc,cstr,uc)->t(Fields(loc,cstr,Univ_map.adduckeyv))stateletset_many:typeak.Univ_map.t->(a,k)parser->(a,k)parser=funmaptctxstate->matchctxwith|Values(loc,cstr,uc)->t(Values(loc,cstr,Univ_map.superposeucmap))state|Fields(loc,cstr,uc)->t(Fields(loc,cstr,Univ_map.superposeucmap))stateletloc:typek.kcontext->k->Loc.t*k=functxstate->matchctxwith|Values(loc,_,_)->(loc,state)|Fields(loc,_,_)->(loc,state)letat_eos:typek.kcontext->k->bool=functxstate->matchctxwith|Values_->state=[]|Fields_->Name.Map.is_emptystate.unparsedleteosctxstate=(at_eosctxstate,state)letif_eos~then_~else_ctxstate=ifat_eosctxstatethenthen_ctxstateelseelse_ctxstateletrepeat:'at->'alistt=letreclooptaccctxl=matchlwith|[]->(List.revacc,[])|_->letx,l=tctxlinloopt(x::acc)ctxlinfuntctxstate->loopt[]ctxstateletresult:typeak.kcontext->a*k->a=functx(v,state)->matchctxwith|Values(_,cstr,_)->beginmatchstatewith|[]->v|sexp::_->matchcstrwith|None->of_sexp_errorf(Ast.locsexp)"This value is unused"|Somes->of_sexp_errorf(Ast.locsexp)"Too many argument for %s"send|Fields_->beginmatchName.Map.choosestate.unparsedwith|None->v|Some(name,{entry;_})->letname_loc=matchentrywith|List(_,s::_)->Ast.locs|_->assertfalseinof_sexp_errorf~hint:{on=name;candidates=state.known}name_loc"Unknown field %s"nameendletparsetcontextsexp=letctx=Values(Ast.locsexp,None,context)inresultctx(tctx[sexp])letcapturectxstate=letft=resultctx(tctxstate)in(f,[])letend_of_list(Values(loc,cstr,_))=matchcstrwith|None->letloc={locwithstart=loc.stop}inof_sexp_errorfloc"Premature end of list"|Somes->of_sexp_errorfloc"Not enough arguments for %s"s[@@inlinenever]letnextfctxsexps=matchsexpswith|[]->end_of_listctx|sexp::sexps->(fsexp,sexps)[@@inlinealways]letnext_with_user_contextfctxsexps=matchsexpswith|[]->end_of_listctx|sexp::sexps->(f(get_user_contextctx)sexp,sexps)[@@inlinealways]letpeek_ctxsexps=matchsexpswith|[]->(None,sexps)|sexp::_->(Somesexp,sexps)[@@inlinealways]letpeek_exnctxsexps=matchsexpswith|[]->end_of_listctx|sexp::_->(sexp,sexps)[@@inlinealways]letjunk=nextignoreletjunk_everything:typek.(unit,k)parser=functxstate->matchctxwith|Values_->((),[])|Fields_->((),{statewithunparsed=Name.Map.empty})letkeywordkwd=next(function|Atom(_,s)whenAtom.to_strings=kwd->()|sexp->of_sexp_errorf(Ast.locsexp)"'%s' expected"kwd)letmatch_keywordl~fallback=peek>>=function|Some(Atom(_,As))->beginmatchList.assoclswith|Somet->junk>>>t|None->fallbackend|_->fallbackletuntil_keywordkwd~before~after=letrecloopacc=peek>>=function|None->return(List.revacc,None)|Some(Atom(_,As))whens=kwd->junk>>>after>>=funx->return(List.revacc,Somex)|_->before>>=funx->loop(x::acc)inloop[]letplain_stringf=next(function|Atom(loc,As)|Quoted_string(loc,s)->f~locs|Template{loc;_}|List(loc,_)->of_sexp_errorloc"Atom or quoted string expected")letentert=next_with_user_context(funucsexp->matchsexpwith|List(loc,l)->letctx=Values(loc,None,uc)inresultctx(tctxl)|sexp->of_sexp_error(Ast.locsexp)"List expected")letif_list~then_~else_=peek_exn>>=function|List_->then_|_->else_letif_paren_colon_form~then_~else_=peek_exn>>=function|List(_,Atom(loc,As)::_)whenString.is_prefixs~prefix:":"->letname=String.drops1inenter(junk>>=fun()->then_>>|funf->f(loc,name))|_->else_letfixf=letrecp=lazy(fr)andrast=(Lazy.forcep)astinrletloc_between_states:typek.kcontext->k->k->Loc.t=functxstate1state2->matchctxwith|Values_->beginmatchstate1with|sexp::restwhenrest==state2->(* common case *)Ast.locsexp|[]->let(Values(loc,_,_))=ctxin{locwithstart=loc.stop}|sexp::rest->letloc=Ast.locsexpinletrecsearchlastl=ifl==state2then{locwithstop=(Ast.loclast).stop}elsematchlwith|[]->let(Values(loc,_,_))=ctxin{(Ast.locsexp)withstop=loc.stop}|sexp::rest->searchsexprestinsearchsexprestend|Fields_->letparsed=Name.Map.mergestate1.unparsedstate2.unparsed~f:(fun_keybeforeafter->matchbefore,afterwith|Some_,None->before|_->None)inmatchName.Map.valuesparsed|>List.map~f:(funf->Ast.locf.Fields.Unparsed.entry)|>List.sort~compare:(funab->Int.comparea.Loc.start.pos_cnumb.start.pos_cnum)with|[]->let(Fields(loc,_,_))=ctxinloc|first::l->letlast=List.fold_leftl~init:first~f:(fun_x->x)in{firstwithstop=last.stop}letlocatedtctxstate1=letx,state2=tctxstate1in((loc_between_statesctxstate1state2,x),state2)letraw=next(funx->x)letunit=next(function|List(_,[])->()|sexp->of_sexp_error(Ast.locsexp)"() expected")letbasicdescf=next(function|Template{loc;_}|List(loc,_)|Quoted_string(loc,_)->of_sexp_errorfloc"%s expected"desc|Atom(loc,s)->matchf(Atom.to_strings)with|Result.Error()->of_sexp_errorfloc"%s expected"desc|Okx->x)letstring=plain_string(fun~loc:_x->x)letint=basic"Integer"(funs->matchint_of_stringswith|x->Okx|exception_->Result.Error())letfloat=basic"Float"(funs->matchfloat_of_stringswith|x->Okx|exception_->Result.Error())letpairab=enter(a>>=funa->b>>=funb->return(a,b))lettripleabc=enter(a>>=funa->b>>=funb->c>>=func->return(a,b,c))letlistt=enter(repeatt)letarrayt=listt>>|Array.of_listletoptiont=enter(eos>>=function|true->returnNone|false->t>>|Option.some)letfind_cstrcstrslocnamectxvalues=matchList.assoccstrsnamewith|Somet->resultctx(tctxvalues)|None->of_sexp_errorfloc~hint:{on=name;candidates=List.mapcstrs~f:fst}"Unknown constructor %s"nameletsumcstrs=next_with_user_context(funucsexp->matchsexpwith|Atom(loc,As)->find_cstrcstrslocs(Values(loc,Somes,uc))[]|Template{loc;_}|Quoted_string(loc,_)->of_sexp_errorloc"Atom expected"|List(loc,[])->of_sexp_errorloc"Non-empty list expected"|List(loc,name::args)->matchnamewith|Quoted_string(loc,_)|List(loc,_)|Template{loc;_}->of_sexp_errorloc"Atom expected"|Atom(s_loc,As)->find_cstrcstrss_locs(Values(loc,Somes,uc))args)letenumcstrs=next(function|Quoted_string(loc,_)|Template{loc;_}|List(loc,_)->of_sexp_errorloc"Atom expected"|Atom(loc,As)->matchList.assoccstrsswith|Somevalue->value|None->of_sexp_errorfloc~hint:{on=s;candidates=List.mapcstrs~f:fst}"Unknown value %s"s)letbool=enum[("true",true);("false",false)]letmap_validatet~fctxstate1=letx,state2=tctxstate1inmatchfxwith|Result.Okx->(x,state2)|Errormsg->letloc=loc_between_statesctxstate1state2inof_sexp_errorfloc"%s"msgletfield_missinglocname=of_sexp_errorfloc"field %s missing"name[@@inlinenever]letfield_present_too_many_times_nameentries=matchentrieswith|_::second::_->of_sexp_errorf(Ast.locsecond)"Field %S is present too many times"name|_->assertfalseletmultiple_occurrences?(on_dup=field_present_too_many_times)ucnamelast=letreccollectacc(x:Fields.Unparsed.t)=letacc=x.entry::accinmatchx.prevwith|None->acc|Someprev->collectaccprevinon_dupucname(collect[]last)[@@inlinenever]letfind_single?on_dupuc(state:Fields.t)name=letres=Name.Map.findstate.unparsednamein(matchreswith|Some({prev=Some_;_}aslast)->multiple_occurrencesucnamelast?on_dup|_->());resletfieldname?default?on_dupt(Fields(loc,_,uc))state=matchfind_singleucstatename?on_dupwith|Some{values;entry;_}->letctx=Values(Ast.locentry,Somename,uc)inletx=resultctx(tctxvalues)in(x,Fields.consumenamestate)|None->matchdefaultwith|Somev->(v,Fields.add_knownnamestate)|None->field_missinglocnameletfield_oname?on_dupt(Fields(_,_,uc))state=matchfind_singleucstatename?on_dupwith|Some{values;entry;_}->letctx=Values(Ast.locentry,Somename,uc)inletx=resultctx(tctxvalues)in(Somex,Fields.consumenamestate)|None->(None,Fields.add_knownnamestate)letfield_b_genfield_gen?check?on_dupname=field_genname?on_dup(Option.valuecheck~default:(return())>>=fun()->eos>>=function|true->returntrue|_->bool)letfield_b=field_b_gen(field~default:false)letfield_o_b=field_b_genfield_oletmulti_fieldnamet(Fields(_,_,uc))(state:Fields.t)=letrecloopacc(field:Fields.Unparsed.toption)=matchfieldwith|None->acc|Some{values;prev;entry}->letctx=Values(Ast.locentry,Somename,uc)inletx=resultctx(tctxvalues)inloop(x::acc)previnletres=loop[](Name.Map.findstate.unparsedname)in(res,Fields.consumenamestate)letfieldst(Values(loc,cstr,uc))sexps=letunparsed=List.fold_leftsexps~init:Name.Map.empty~f:(funaccsexp->matchsexpwith|List(_,name_sexp::values)->beginmatchname_sexpwith|Atom(_,Aname)->Name.Map.addaccname{Fields.Unparsed.values;entry=sexp;prev=Name.Map.findaccname}|List(loc,_)|Quoted_string(loc,_)|Template{loc;_}->of_sexp_errorloc"Atom expected"end|_->of_sexp_error(Ast.locsexp)"S-expression of the form (<name> <values>...) expected")inletctx=Fields(loc,cstr,uc)inletx=resultctx(tctx{Fields.unparsed;known=[]})in(x,[])letleftover_fields(Fields(_,_,_))state=(Fields.unparsed_aststate,{Fields.known=state.known@Name.Map.keysstate.unparsed;unparsed=Name.Map.empty})letrecordt=enter(fieldst)typekind=|ValuesofLoc.t*stringoption|FieldsofLoc.t*stringoptionletkind:typek.kcontext->k->kind*k=functxstate->matchctxwith|Values(loc,cstr,_)->(Values(loc,cstr),state)|Fields(loc,cstr,_)->(Fields(loc,cstr),state)moduleLet_syntax=structlet($)ft=f>>=funf->t>>|funt->ftletconst=returnendendmoduletypeConv=sigtypetvaldecode:tDecoder.tvalencode:tEncoder.tendletrecto_sexp=function|Atom(Aa)->Sexp.Atoma|Lists->List(List.maps~f:to_sexp)|Quoted_strings->Sexp.Atoms|Templatet->List[Atom"template";Atom(Template.to_string~syntax:Dunet)]moduleIo=structletload?lexerpath~mode=Io.with_lexbuf_from_filepath~f:(Parser.parse~mode?lexer)end