123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121typet={line:int;(* Line number i.e. number of newlines since
start of the file. *)byte_bol:int;(* Byte position at the start of the line. *)byte_col:int;(* Byte position in the current line. *)correction:int;(* Byte column + correction = character column
*)}typerange=t*tletline(p:t):int=p.lineletbyte_offset_bol(p:t):int=p.byte_bolletbyte_columnp=p.byte_colletbyte_offset(p:t):int=p.byte_bol+p.byte_colletcolumn(p:t):int=p.byte_col+p.correctionletstart:t={line=0;byte_bol=0;byte_col=0;correction=0;}letadvance(byte_width:int)(width:int)(p:t):t={pwithbyte_col=p.byte_col+byte_width;correction=p.correction+width-byte_width;}letnewline(byte_width:int)(p:t):t={line=p.line+1;byte_col=0;byte_bol=p.byte_bol+p.byte_col+byte_width;correction=0;}letnext(c:char)(p:t):t=ifc='\n'then{line=p.line+1;byte_bol=p.byte_bol+p.byte_col+1;byte_col=0;correction=0;}else{pwithbyte_col=p.byte_col+1;correction=ifc='\t'thenp.correction+3elseifc<' 'thenp.correction-1elsep.correction}letcorrect(cor:int)(p:t):t={pwithcorrection=p.correction+cor}letis_less_equal(p1:t)(p2:t):bool=letl1,l2=linep1,linep2andc1,c2=columnp1,columnp2in(l1<l2||(l1=l2&&c1<=c2))letis_valid_range((p1,p2):range):bool=is_less_equalp1p2letmerge((p1,_):range)((_,p2):range):range=assert(is_less_equalp1p2);p1,p2