123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662openStdunetypeast=Ast.t=|AtomofLoc.t*Atom.t|Quoted_stringofLoc.t*string|TemplateofTemplate.t|ListofLoc.t*astlisttypehint={on:string;candidates:stringlist}moduleName=structmoduleT=structtypet=stringletcompareab=letalen=String.lengthaandblen=String.lengthbinmatchInt.comparealenblenwith|Eq->String.compareab|ne->neletto_dyn=Dyn.Encoder.stringendincludeTmoduleMap=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->(matchx.Unparsed.prevwith|None->loop(x.entry::acc)xs|Somep->loop(x.entry::acc)(p::xs))inloop[](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=actxstateinbctxstatelet(let*)=(>>=)let(let+)=(>>|)let(and+)abctxstate=leta,state=actxstateinletb,state=bctxstatein((a,b),state)letmapt~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)leteos:typek.kcontext->k->bool*k=functxstate->matchctxwith|Values_->(state=[],state)|Fields_->(Name.Map.is_emptystate.unparsed,state)letrepeat:'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,_)->(matchstatewith|[]->v|sexp::_->(matchcstrwith|None->User_error.raise~loc:(Ast.locsexp)[Pp.text"This value is unused"]|Somes->User_error.raise~loc:(Ast.locsexp)[Pp.textf"Too many argument for %s"s]))|Fields_->(matchName.Map.choosestate.unparsedwith|None->v|Some(name,{entry;_})->letname_loc=matchentrywith|List(_,s::_)->Ast.locs|_->assertfalseinUser_error.raise~loc:name_loc~hints:(User_message.did_you_meanname~candidates:state.known)[Pp.textf"Unknown field %s"name])letparsetcontextsexp=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}inUser_error.raise~loc[Pp.text"Premature end of list"]|Somes->User_error.raise~loc[Pp.textf"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(_,As)whens=kwd->()|sexp->User_error.raise~loc:(Ast.locsexp)[Pp.textf"'%s' expected"kwd])letatom_matchingf~desc=next(funsexp->matchmatchsexpwith|Atom(_,As)->fs|_->Nonewith|Somex->x|None->User_error.raise~loc:(Ast.locsexp)[Pp.textf"%s expected"desc])letuntil_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,_)->User_error.raise~loc[Pp.text"Atom or quoted string expected"])letfilename=plain_string(fun~locs->matchswith|"."|".."->User_error.raise~loc[Pp.textf"'.' and '..' are not valid filenames"]|fn->fn)letentert=next_with_user_context(funucsexp->matchsexpwith|List(loc,l)->letctx=Values(loc,None,uc)inresultctx(tctxl)|sexp->User_error.raise~loc:(Ast.locsexp)[Pp.text"List expected"])let(<|>)=(* Before you read this code, close your eyes and internalise the fact that
this code is temporary. It is a temporary state as part of a larger work to
turn [Decoder.t] into a pure applicative. Once this is done, this function
will be implemented in a better way and with a much cleaner semantic. *)letapproximate_how_much_input_a_failing_branch_consumed(exn:Exn_with_backtrace.t)=Printexc.raw_backtrace_lengthexn.backtraceinletcompare_input_consumedexn1exn2=Int.compare(approximate_how_much_input_a_failing_branch_consumedexn1)(approximate_how_much_input_a_failing_branch_consumedexn2)infunabctxstate->tryactxstatewithexn_a->(letexn_a=Exn_with_backtrace.captureexn_aintrybctxstatewithexn_b->letexn_b=Exn_with_backtrace.captureexn_binExn_with_backtrace.reraise(matchcompare_input_consumedexn_aexn_bwith|Gt->exn_a|Eq|Lt->exn_b))letfixf=letrecp=lazy(fr)andrast=(Lazy.forcep)astinrletloc_between_states:typek.kcontext->k->k->Loc.t=functxstate1state2->matchctxwith|Values_->(matchstate1with|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->searchsexprestinsearchsexprest)|Fields_->(letparsed=Name.Map.mergestate1.unparsedstate2.unparsed~f:(fun_keybeforeafter->match(before,after)with|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=nextFun.idletbasic_locdescf=next(function|Template{loc;_}|List(loc,_)|Quoted_string(loc,_)->User_error.raise~loc[Pp.textf"%s expected"desc]|Atom(loc,s)->(matchf~loc(Atom.to_strings)with|None->User_error.raise~loc[Pp.textf"%s expected"desc]|Somex->x))letbasicdescf=basic_locdesc(fun~loc:_->f)letstring=plain_string(fun~loc:_x->x)letint=basic"Integer"Int.of_stringletfloat=basic"Float"Float.of_stringletpairab=enter(a>>=funa->b>>=funb->return(a,b))lettripleabc=enter(a>>=funa->b>>=funb->c>>=func->return(a,b,c))letunit_numbernamesuffixes=letunit_number_of_string~locs=letpossible_suffixes()=String.concat~sep:", "(List.map~f:fstsuffixes)inletn,suffix=letfc=not(Char.codec>=Char.code'0'&&Char.codec<=Char.code'9')inmatchString.findis~fwith|None->User_error.raise~loc[Pp.textf"missing suffix, use one of %s"(possible_suffixes())]|Somei->String.split_nsiinletfactor=matchList.assocsuffixessuffixwith|Somef->f|None->User_error.raise~loc[Pp.textf"invalid suffix, use one of %s"(possible_suffixes())]inOption.map~f:((*)factor)(Int.of_stringn)inbasic_locnameunit_number_of_stringletduration=unit_number"Duration"[("s",1);("m",60);("h",60*60)]letbytes_unit=unit_number"Byte amount"[("B",1);("kB",1000);("KB",1000);("MB",1000*1000);("GB",1000*1000*1000)]letmaybet=t>>|Option.some<|>returnNoneletfind_cstrcstrslocnamectxvalues=matchList.assoccstrsnamewith|Somet->resultctx(tctxvalues)|None->User_error.raise~loc~hints:(User_message.did_you_meanname~candidates:(List.mapcstrs~f:fst))[Pp.textf"Unknown constructor %s"name]letsum?(force_parens=false)cstrs=next_with_user_context(funucsexp->matchsexpwith|Atom(loc,As)whennotforce_parens->find_cstrcstrslocs(Values(loc,Somes,uc))[]|Atom(loc,_)|Template{loc;_}|Quoted_string(loc,_)|List(loc,[])->User_error.raise~loc[Pp.textf"S-expression of the form %s expected"(ifforce_parensthen"(<atom> ...)"else"(<atom> ...) or <atom>")]|List(loc,name::args)->(matchnamewith|Quoted_string(loc,_)|List(loc,_)|Template{loc;_}->User_error.raise~loc[Pp.text"Atom expected"]|Atom(s_loc,As)->find_cstrcstrss_locs(Values(loc,Somes,uc))args))letenumcstrs=next(function|Quoted_string(loc,_)|Template{loc;_}|List(loc,_)->User_error.raise~loc[Pp.text"Atom expected"]|Atom(loc,As)->(matchList.assoccstrsswith|Somevalue->value|None->User_error.raise~loc[Pp.textf"Unknown value %s"s]~hints:(User_message.did_you_means~candidates:(List.mapcstrs~f:fst))))letbool=enum[("true",true);("false",false)]letmap_validatet~fctxstate1=letx,state2=tctxstate1inmatchfxwith|Result.Okx->(x,state2)|Error(msg:User_message.t)->letmsg=matchmsg.locwith|Some_->msg|None->{msgwithloc=Some(loc_between_statesctxstate1state2)}inraise(User_error.Emsg)(** TODO: Improve consistency of error messages, e.g. use %S consistently for
field names: see [field_missing] and [field_present_too_many_times]. *)letfield_missinglocname=User_error.raise~loc[Pp.textf"field %s missing"name][@@inlinenever]letfield_present_too_many_times_nameentries=matchentrieswith|_::second::_->User_error.raise~loc:(Ast.locsecond)[Pp.textf"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_missinglocname)letfield_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(let*()=Option.valuecheck~default:(return())ineos>>=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)->(matchname_sexpwith|Atom(_,Aname)->Name.Map.setaccname{Fields.Unparsed.values;entry=sexp;prev=Name.Map.findaccname}|List(loc,_)|Quoted_string(loc,_)|Template{loc;_}->User_error.raise~loc[Pp.text"Atom expected"])|_->User_error.raise~loc:(Ast.locsexp)[Pp.text"S-expression of the form (<name> <values>...) expected"])inletctx=Fields(loc,cstr,uc)inletx=resultctx(tctx{Fields.unparsed;known=[]})in(x,[])letleftover_fields_generictmore_fields(Fields(loc,cstr,uc))state=letx=letctx=Values(loc,cstr,uc)inresultctx(repeattctx(Fields.unparsed_aststate))in(x,{Fields.known=state.known@more_fields;unparsed=Name.Map.empty})letleftover_fieldsctx(state:Fields.t)=leftover_fields_genericraw(Name.Map.keysstate.unparsed)ctxstateletleftover_fields_as_sumscstrs=leftover_fields_generic(sumcstrs)(List.mapcstrs~f:fst)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)lettraversel~fctxstate=Tuple.T2.swap(List.fold_map~init:statel~f:(funstatex->Tuple.T2.swap(fxctxstate)))letall=traverse~f:(funx->x)letfields_missing_need_exactly_onelocnames=User_error.raise~loc[Pp.textf"fields %s are all missing (exactly one is needed)"(String.concat~sep:", "names)][@@inlinenever]letfields_mutual_exclusion_violationlocnames=User_error.raise~loc[Pp.textf"fields %s are mutually exclusive"(String.concat~sep:", "names)][@@inlinenever]letfields_mutually_exclusive?on_dup?defaultfields((Fields(loc,_,_):_context)asctx)state=letres,state=traverse~f:(fun(name,parser)->field_oname?on_dupparser>>|funres->(name,res))fieldsctxstateinmatchList.filter_mapres~f:(function|name,Somex->Some(name,x)|_,None->None)with|[]->(letnames=List.mapfields~f:fstinmatchdefaultwith|None->fields_missing_need_exactly_onelocnames|Somedefault->(default,state))|[(_name,res)]->(res,state)|_::_::_asresults->letnames=List.map~f:fstresultsinfields_mutual_exclusion_violationlocnames