123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119(* Based on
* https://github.com/smolkaj/ocaml-parsing/blob/master/src/LexBuffer.ml *)(** A custom lexbuffer that automatically keeps track of the source location.
This module is a thin wrapper arounds sedlexing's default buffer, which does
not provide this functionality. *)typet={buf:Sedlexing.lexbuf;mutablepos:Lexing.position;mutablepos_mark:Lexing.position;mutablelast_char:intoption;mutablelast_char_mark:intoption;}(** the lex buffer type *)letof_sedlex?(file="<n/a>")?posbuf=letpos=matchposwith|None->{Lexing.pos_fname=file;pos_lnum=1;(* line number *)pos_bol=0;(* offset of beginning of current line *)pos_cnum=0(* total offset *);}|Somep->pin{buf;pos;pos_mark=pos;last_char=None;last_char_mark=None}letof_ascii_string?poss=of_sedlex?pos(Sedlexing.Latin1.from_strings)letof_ascii_filefile=letchan=open_infileinof_sedlex~file(Sedlexing.Latin1.from_channelchan)(** The next four functions are used by sedlex internally.
See https://www.lexifi.com/sedlex/libdoc/Sedlexing.html. *)letmarklexbufp=lexbuf.pos_mark<-lexbuf.pos;lexbuf.last_char_mark<-lexbuf.last_char;Sedlexing.marklexbuf.bufpletbacktracklexbuf=lexbuf.pos<-lexbuf.pos_mark;lexbuf.last_char<-lexbuf.last_char_mark;Sedlexing.backtracklexbuf.bufletstartlexbuf=lexbuf.pos_mark<-lexbuf.pos;lexbuf.last_char_mark<-lexbuf.last_char;Sedlexing.startlexbuf.buf(** location of next character *)letnext_loclexbuf={lexbuf.poswithpos_cnum=lexbuf.pos.pos_cnum+1}letcr=Char.code'\r'(** next character *)letnextlexbuf=letc=Sedlexing.nextlexbuf.bufinletpos=next_loclexbufinletch=matchcwith|None->None|Somec->(trySome(Uchar.to_charc)withInvalid_argument_->None)in(matchchwith|Some'\r'->lexbuf.pos<-{poswithpos_bol=pos.pos_cnum-1;pos_lnum=pos.pos_lnum+1}|Some'\n'whennot(lexbuf.last_char=Somecr)->lexbuf.pos<-{poswithpos_bol=pos.pos_cnum-1;pos_lnum=pos.pos_lnum+1}|Some'\n'->()|_->lexbuf.pos<-pos);(matchcwith|None->lexbuf.last_char<-None|Somec->lexbuf.last_char<-Some(Uchar.to_intc));clet__private__next_intlexbuf=matchnextlexbufwith|None->-1|Somex->Uchar.to_intxletrawlexbuf=Sedlexing.lexemelexbuf.bufletlatin1?(skip=0)?(drop=0)lexbuf=letlen=Sedlexing.lexeme_lengthlexbuf.buf-skip-dropinSedlexing.Latin1.sub_lexemelexbuf.bufskiplenletutf8?(skip=0)?(drop=0)lexbuf=letlen=Sedlexing.lexeme_lengthlexbuf.buf-skip-dropinSedlexing.Utf8.sub_lexemelexbuf.bufskiplenletcontainer_lnum_ref=ref0letfix_locloc=letfix_pospos=(* It looks like lex_buffer.ml returns a position with 2 extra
* chars for parsed lines after the first one. Bug? *)letpos_cnum=ifpos.Lexing.pos_lnum>!container_lnum_refthenpos.Lexing.pos_cnum-2elsepos.Lexing.pos_cnumin{poswithLexing.pos_cnum}inletloc_start=fix_posloc.Location.loc_startinletloc_end=fix_posloc.Location.loc_endin{locwithLocation.loc_start;loc_end}letmake_loc?(loc_ghost=false)start_posend_pos:Location.t={Location.loc_start=start_pos;loc_end=end_pos;loc_ghost}letmake_loc_and_fix?(loc_ghost=false)start_posend_pos:Location.t=make_loc~loc_ghoststart_posend_pos|>fix_loc