You can search for identifiers within the package.
in-package search v0.2.0
Source file pratter.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128(* Copyright (C) Gabriel Hondet.
Subject to the BSD-3-Clause license *)letor_else(x:'aoption)(f:unit->'a):'a=matchxwithSomex->x|None->f()typeassociativity=Left|Right|Neithertypefixity=Infixofassociativity|Prefix|Postfixtype'terror=[`Op_conflictof't|`Too_few_arguments]type('a,'b)result=('a,'berror)Stdlib.resulttype('tok,'a)parser='tokSeq.t->('a*'tokSeq.t,'tok)result(** Parses ['tok] to ['a]. *)letpure(x:'b):('a,'b)parser=funstrm->Ok(x,strm)letbind(typeab)(p0:('tok,a)parser)(f:a->('tok,b)parser):('tok,b)parser=funinp->matchp0inpwithError_ase->e|Ok(out,inp')->foutinp'letfmap(f:'a->'b)(p:('tok,'a)parser):('tok,'b)parser=funinp->Result.map(fun(x,y)->(fx,y))(pinp)letfail(e:'ierror):('i,_)parser=fun_->Errore(* Put back a token in the stream of input. *)letpush(x:'i):('i,unit)parser=funinp->Ok((),(* This expression becomes [Seq.cons] in ocaml 4.11 *)fun()->Seq.Cons(x,inp))(** Parse a single token if there is one. *)lettok:('tok,'tokoption)parser=funinp->(* Can be replaced by [Seq.uncons] from ocaml 4.14 *)matchinp()with|Seq.Nil->Ok(None,Seq.empty)|Seq.Cons(t,rest)->Ok(Somet,rest)let(let*)=bindletrun(p:('i,'o)parser)(inp:_Seq.t):('o,_)result=Result.mapfst(pinp)leton_prefix(f:float->'a->'b):fixity*float*'a->'boption=function|Prefix,prio,s->Some(fprios)|(Postfix|Infix_),_,_->Noneleton_postfix(f:float->'a->'b):fixity*float*'a->'boption=function|Postfix,prio,s->Some(fprios)|(Prefix|Infix_),_,_->Noneleton_infix(f:associativity->float->'a->'b):fixity*float*'a->'boption=function|Infixassoc,prio,s->Some(fassocprios)|(Postfix|Prefix),_,_->Noneletexpression(typeab)~(appl:b->b->b)~(token:a->b)~(ops:a->(fixity*float*b)list):(a,b)parser=(* [nud tbl strm t] (for null denotation) is the production of term [t] with
{b no} left context. If [t] is not a prefix operator, [nud] is the
identity. Otherwise, the output is a production rule. *)letrecnud(t:a):(a,b)parser=or_else(List.find_map(on_prefix(funrbpt'->fmap(applt')(expression~rbp~rassoc:Neither)))(opst))@@fun()->pure(tokent)(* [led ~strm ~left t assoc bp] is the production of term [t] with
left context [left]. We have the invariant that [t] is a binary operator
with associativity [assoc] and binding power [bp]. This invariant is
ensured while called in {!val:expression}. *)andled~lefttrassocbp:(a,b)parser=letrbp=matchrassocwith|Right->bp*.(1.-.epsilon_float)|Left|Neither->bpinfmap(appl(appltleft))(expression~rbp~rassoc)(* [expression ~rbp ~rassoc strm] parses next token of stream
[strm] with previous operator having a right binding power [~rbp] and
associativity [~rassoc]. *)andexpression~rbp~rassoc=(* [aux left] inspects the stream and may consume one of its elements, or
return [left] unchanged. *)letrecaux(left:b):(a,b)parser=let*next=tokinmatchnextwith|None->pureleft|Somept->letops=opsptin(* Process the infix case *)letifxlassoclbpnext=iflbp>rbp||(lbp=rbp&&lassoc=Right&&rassoc=Right)thenlet*t=led~leftnextlassoclbpinauxtelseiflbp<rbp||(lbp=rbp&&lassoc=Left&&rassoc=Left)then(* Put back *)let*()=pushptinpureleftelsefail(`Op_conflictpt)inletpostfixlbpnext=iflbp>rbpthenaux(applnextleft)elseiflbp=rbpthenfail(`Op_conflictpt)elselet*()=pushptinpureleftinor_else(List.find_map(on_infixifx)ops)@@fun()->or_else(List.find_map(on_postfixpostfix)ops)@@fun()->let*right=nudptinaux(applleftright)inlet*next=tokinmatchnextwith|None->fail`Too_few_arguments|Somenext->let*left=nudnextinauxleftinexpression~rbp:neg_infinity~rassoc:Neither