123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327openBatListopenBatLazyListopenBatIOopenBatPrintftype'astate=|Eof|Stateof'atype'areport=Report of('astate*string*'areport)listlet(&&&)(Reportl)(Reportl')=Report(l@l')letdebug_mode=reffalse(** {3 Positions} *)moduleSource=structtype('a,'b)t=('a*'b)BatLazyList.tletof_lazy_listlinit f=letrecauxlacc=matchgetlwith|None->nil|Some(h,t)->letacc'=fhaccinlazy(Cons((h,acc'),(auxtacc')))inauxlinitletof_enuml=of_lazy_list (of_enum l)(**TODO: Handle EOF!*)letof_lexer_l=assertfalse(** LazyList.of_enum (BatEnum.from (fun () ->
let open Lexing in
l.refill_buff l;
(l.lex_buffer, (l.lex_start_p, l.lex_curr_p))))*)letget_statel=matchpeeklwith|Some(_,s)->States|None->Eofletset_full_statelinitf=letrecauxlacc=matchgetlwith|None->nil|Some((h,_),t)->letacc'=fhaccinlazy(Cons((h,acc'),(auxtacc')))inauxlinitendopenSourcetype('a,'b,'c)result=|Successof'b*('a,'c)Source.t(**Succeed and consume.*)|Backtrackof'b*'creport*('a,'c)Source.t(**Succeed because of backtracking, typically without consuming.*)|Setbackof'creport(**Error, backtracking in progress.*)|Failureof'creport(**Fatal error.*)type('a,'b,'c)t=('a,'c)Source.t->('a,'b,'c)resultletapplype=pe(**To improve reusability*)(** {3 Error-handling} *)(*exception Backtrack of Obj.t report*)(**Recoverable error.
These errors are caused by [fail].*)(*exception Fail of Obj.t report*)(**Fatal error.
These errors are caused by [must].*)letfail_e=Setback(Report[])letsucceedve=Success(v,e)letbacktrackedvre=Backtrack(v,r,e)letreturn=succeedletfatal_e=Failure(Report[])(* Primitives *)letsatisfyfe=matchgetewith|Some((x,_),t)whenfx->succeedxt|_->faileletdepth=ref0letlabelspe=ifBatString.is_emptysthenmatchapplypewith|Success_asx->x|Setback_c->Setback(Report[])|Failure_c->Failure(Report[])|Backtrack(b,_c,t)->Backtrack(b,Report[],t)elseletmake_reportc=Report[get_statee,s,c]inif!debug_modethenbegineprintf"%*s>>> %s\n"!depth" "s;incrdepth;flush_all()end;matchapplypewith|Success_asx->if!debug_modethenbegindecrdepth;eprintf"%*s<<< %s\n"!depth" "s;flush_all()end;x|Setbackc->if!debug_modethenbegindecrdepth;eprintf"%*s^^^ %s\n"!depth" "s;flush_all()end;Setback (make_reportc)|Failurec->if!debug_modethenbegindecrdepth;eprintf"%*s!!! %s\n"!depth" "s;flush_all()end;Failure (make_reportc)|Backtrack(b,c,t)->if!debug_modethenbegindecrdepth;eprintf"%*s/// %s\n"!depth" "s;flush_all()end;Backtrack (b,make_reportc,t)letmustpe=matchapplypewith|Setbackx->Failurex|y->yletshouldpe=matchapplypewith|Failurex->Setbackx|y->yleteitherle=letrecauxerr=function|[]->Setback(Reporterr)|h::t->matchapplyhewith|Success_|Failure_|Backtrack(_,_,_)asresult->result|Setback(Reportlabels)->aux(err@labels)tinaux []llet(<|>)p1p2=either[p1;p2]letmaybepe=matchapplypewith|Setbackc->Backtrack(None,c,e)|Success(result,rest)->Success(Someresult,rest)|Backtrack(result,report,rest)->Backtrack(Someresult,report,rest)|Failure_asresult->resultlet(~?)=maybe(*
[bind m f e]
If [m] succeeded by backtracking and [f] fails or
succeeds by backtracking, merge the reports of [m] and [f].
*)letbindmfe=matchapplymewith|Setback_|Failure_asresult->result|Success(result,rest)->applyfresultrest|Backtrack(result,report,rest)->matchapplyfresultrestwith|Backtrack(result',report',rest')->Backtrack (result',report&&&report',rest')|Setbackreport'->Setback (report&&&report')|Failure report'->Failure (report&&&report')|Success _asresult ->resultlet(>>=)=bindlet(>>>)pq=p>>=fun_->qletconspq=p>>=funp_result->q>>=funq_result->return(p_result::q_result)let(>::)=conslet statee=succeed (get_statee)eleteofe=label"Endof file"(fune->matchgetewith|None->succeed()e|_->faile)eletanye=label"Anything"(fune->matchgetewith|None->faile|Some((x,_),t)->succeedxt)eletzero_plus?seppe=letp'=matchsepwith|None ->p|Somes->s>>>pinletrecauxaccl=matchapplyp'lwith|Success(x,rest)->aux(x::acc)rest|Backtrack(result,report,rest)->backtracked(List.rev(result::acc))reportrest|Setbackreport ->backtracked (List.revacc)reportl|Failure _asresult ->resultinmatchapplypewith|Success(x,rest)->aux[x]rest|Backtrack(result,report,rest)->backtracked[result]reportrest|Setbackreport->backtracked []reporte|Failure_asresult->resultlet(~*)p=zero_pluspletignore_zero_plus?seppe=letp'=match sepwith|None ->p|Somes->s>>>pinletrecauxl=matchapplyp'lwith|Success(_x,rest)->auxrest|Backtrack(_result,report,rest)->backtracked ()reportrest|Setbackreport ->backtracked ()reportl|Failure_asresult ->resultinmatchapplypewith|Success(_,rest)->auxrest|Backtrack(_result,report,rest)->backtracked ()reportrest|Setbackreport->backtracked ()reporte|Failure_asresult->resultletone_plus?sepp=p>::matchsepwith|None->zero_plusp|Somes->zero_plus(s>>>p)let(~+)p=one_pluspletignore_one_plus?sepp=p>>>matchsepwith|None->ignore_zero_plusp|Somes->ignore_zero_plus(s>>>p)(** [prefix t l] returns [h] such that [[h::t] = l]*)letprefixsuffixl=letrecauxaccrest=matchgetrestwith|None->[]|Some(h,t)whent==suffix->List.rev(h::acc)|Some(h,t)->aux(h::acc)tinaux[]lletscanpe=let just_prefixrest=List.mapfst(prefixreste)inmatchapplypewith(*First proceed with parsing*)|Success(_result,rest)->succeed (just_prefix rest)rest|Backtrack(_result,report,rest)->backtracked (just_prefix rest)reportrest|Setback_|Failure _asresult->resultletlookaheadpe=match applypewith|Setbackc->Backtrack(None,c,e)|Success(result,_)->Success(Someresult,e)|Backtrack(result,report,_)->Backtrack(Someresult,report,e)|Failure_asresult->resultletinterpret_result=function|Setbackf|Failuref->BatInnerPervasives.Errorf|Success(r,_)|Backtrack(r,_,_)->BatInnerPervasives.Okrletsuspend:('a,'b,'c)t->('a,(unit->('b,'creport)BatInnerPervasives.result),'c)t=funse->letresume()=interpret_result(se)inSuccess(resume,e)letrunpe=interpret_result (applype)letsource_mappe=letrecauxe=matchpeekewith|None->nil|Some(_,c)->matchapplypewith|Success(result,rest)->lazy(Cons((result,c),(auxrest)))|Backtrack(result,_,rest)->lazy(Cons((result,c),(auxrest)))|Setback_|Failure _->nil(*@TODO: improve error reporting !*)inauxe(**
{3 Utilities}*)letfilterfp=p>>=funx->iffxthenreturnxelsefailletexactlyx=satisfy((=)x)letpost_mapfp=p>>=funx->return(fx)lettimesnp=letrecauxacci=ifi>0thenp>>=funx->(aux(x::acc)(i-1))elsereturnaccin(aux[]n)>>=funx->return(List.revx)let(^^)pn=timesnpletone_ofle=letexistsx=List.exists((=)x)linsatisfyexistseletnone_ofle=letfor_allx=List.for_all((<>)x)linsatisfy for_alleletrangeab=satisfy(funx->a<=x&&x<=b)letsatf=(satisfyf)>>>return()moduleInfix=structlet(<|>),(~?),(>>=),(>>>),(>::),(~*),(~+),(^^)=(<|>),(~?),(>>=),(>>>),(>::),(~*),(~+),(^^)end