123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133(* This file is part of Markup.ml, released under the MIT license. See
LICENSE.md for details, or visit https://github.com/aantron/markup.ml. *)openCommontype'at={mutablef:exncont->unitcont->'acont->unit}letmakef={f}letconstructc=lets=refNonein(funthrowek->match!swith|None->cthrow(funs'->s:=Somes';s'.fthrowek)|Somes'->s'.fthrowek)|>makeletempty()=(fun_e_->e())|>makeletnext{f}throwek=fthrowekletnext_option{f}throwk=fthrow(fun()->kNone)(funv->k(Somev))letnext_expected{f}throwk=fthrow(fun()->throw(Failure"stream empty"))kletnext_nnsthrowk=ifn<0thenthrow(Invalid_argument"n is negative")elseletreciterateacc=function|0->k(List.revacc)|n->nextsthrow(fun()->iterateacc0)(funv->iterate(v::acc)(n-1))initerate[]nletpush({f}ass)v=s.f<-fun__k->s.f<-f;kvletpush_options=function|None->()|Somev->pushsvletpush_list({f}ass)=function|[]->()|vs->letremainder=refvsins.f<-funthrowek->match!remainderwith|[]->s.f<-f;fthrowek|v::vs->remainder:=vs;kvletpeeksthrowek=nextsthrowe(funv->pushsv;kv)letpeek_optionsthrowk=peeksthrow(fun()->kNone)(funv->k(Somev))letpeek_expectedsthrowk=peeksthrow(fun()->throw(Failure"stream empty"))kletpeek_nnsthrowk=next_nnsthrow(funvs->push_listsvs;kvs)lettapg({f}ass)=(s.f<-funthrowek->fthrowe(funv->gv;kv));fun()->s.f<-fletcheckpoints=letbuffer=ref[]inlets'=(funthrowek->s.fthrowe(funv->buffer:=v::!buffer;kv))|>makeinletrestore()=push_lists(List.rev!buffer)ins',restorelettransformfinits=letcurrent_acc=ref(Someinit)inletto_emit=ref[]inletrecoperatethrowek=match!to_emitwith|v::more->to_emit:=more;kv|[]->match!current_accwith|None->e()|Someacc->nextsthrowe(funv->faccvthrow(fun(vs,acc')->to_emit:=vs;current_acc:=acc';operatethrowek))inmakeoperateletmapfs=(funthrowek->nextsthrowe(funv->fvthrowk))|>makeletrecfoldfvsthrowk=nextsthrow(fun()->kv)(funv'->fvv'throw(funv''->foldfv''sthrowk))letiterfsthrowk=fold(fun()vthrowk->fvthrowk)()sthrowkletfilter_mapfs=letrecemitthrowek=nextsthrowe(funv->fvthrow(function|None->emitthrowek|Somev->kv))inmakeemitletfilterfs=s|>filter_map(funvthrowk->fvthrow(function|true->k(Somev)|false->kNone))letof_listl=letl=reflin(fun_ek->match!lwith|[]->e()|v::l'->l:=l';kv)|>makeletto_liststhrowk=fold(funlv_k->k(v::l))[]sthrow(funl->k(List.revl))letenumerates=letindex=ref0ins|>map(funv_k->index:=!index+1;k((!index-1),v))