123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081typepoint={line:int;column:int;}typespan={file:string;start:point;end_:point;}type+'awith_location={location:span;value:'a;}letatlocationvalue={location;value}letlocation{location;_}=locationletvalue{value;_}=valueletmapfannotated={annotatedwithvalue=fannotated.value}letsameannotatedvalue={annotatedwithvalue}letspanspans=matchspanswith|[]->{file="_none_";start={line=1;column=0;};end_={line=1;column=0;};}|first::spans->letlast=List.fold_left(fun_span->span)firstspansin{file=first.file;start=first.start;end_=last.end_;}letnudge_startoffsetspan={spanwithstart={span.startwithcolumn=span.start.column+offset}}letset_end_as_offset_from_startoffsetspan={spanwithend_={span.startwithcolumn=span.start.column+offset}}letpoint_in_stringsoffsetpoint=letrecscan_stringlinecolumnindex=ifindex>=offsetthen(line,column)elseifindex>=String.lengthsthen(line,column)elsematchs.[index]with|'\n'->scan_string(line+1)0(index+1)|_->scan_stringline(column+1)(index+1)inletline,column=scan_string000in{line=point.line+line;column=point.column+column}(* Calling this repeatedly on the same string can be optimized, but there is no
evidence yet that performance of this is a problem. *)letin_strings~offset~lengths_span={s_spanwithstart=point_in_stringsoffsets_span.start;end_=point_in_strings(offset+length)s_span.start}