123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119typeviolation=|Indentofint|Alignofint|Align_betweenofint*inttypet={lb:int;(* lower bound of the indentation set *)ub:intoption;(* upper bound of the indentation set *)abs:bool;(* absolute alignment *)}letinitial:t={lb=0;ub=None;abs=false}letcheck_position(pos:int)(ind:t):violationoption=letcheck_indent()=ifind.lb<=posthenNoneelseSome(Indentind.lb)inmatchind.ubwith|None->check_indent()|Someub->ifnotind.absthencheck_indent()elseifind.lb<=pos&&pos<=ubthenNoneelseifind.lb=ubthenSome(Alignind.lb)elseSome(Align_between(ind.lb,ub))lettoken(pos:int)(ind:t):t=assert(check_positionposind=None);ifnotind.absthen(* Normal case. Token are all wrapped with '>=' i.e. they can appear to
the right of the indentation set of the parent. However, if the token
appears within the indentation set of the parent, then it restricts
the upper bound of the indentation set of the parent. A parent can
by definition never be indented more than all its token. *)matchind.ubwith|Someubwhenub<=pos->ind|_->{indwithub=Somepos}else(* First token of an aligned parent. Indentation set consists of exactly
the token position. *){lb=pos;ub=Somepos;abs=false}letalign(ind:t):t={indwithabs=true}letleft_align(ind:t):t={indwithub=Someind.lb;abs=true;}letstart_indent(i:int)(ind:t):t=ifnotind.absthen{lb=ind.lb+i;ub=None;abs=false}elseindletend_indent(i:int)(ind0:t)(ind:t):t=ifnotind0.absthen(* The old lower bound remains. The upper bound must be updated, if the
new indentation has an upper bound. The upper bound is set to the
minimum of both. *)matchind.ubwith|None->ind0|Someub->assert(ind0.lb+i<=ub);{ind0withub=matchind0.ubwith|None->Some(ub-i)|Someub0->Some(minub0(ub-i))}elseind