Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file mli_parser.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203open!CompatmoduleCode_block=structtypet={location:Odoc_model.Location_.span;contents:string}endletdrop_lastlst=matchList.revlstwith|[]->None|last::rev_tl->Some(List.revrev_tl,last)(* drop_first_and_last [1; 2; 3; 4] = Some (1, Some ([2; 3], 4)). *)letdrop_first_and_last=function|[]->None|first::tl->Some(first,drop_lasttl)letslicelines~(start:Odoc_model.Location_.point)~(end_:Odoc_model.Location_.point)=letlines_to_include=Util.Array.slicelines~from:(start.line-1)~to_:(end_.line-1)|>Array.to_listinmatchdrop_first_and_lastlines_to_includewith|None->""|Some(line,None)->String.sublinestart.column(end_.column-start.column)(* Imagine we were slicing the file from (Line 2, Column 3) to (Line 6, Column 7):
0123456789
1 ----------
2 ---[---
3 ---------
4 --
5 ----------
6 -------]--
7 ----------
8 ----------
The case below handles this multiline case, concatenating the included substrings
from lines 2-6 ([lines_to_include]). *)|Some(first_line,Some(stripped,last_line))->letfirst_line=String.subfirst_linestart.column(String.lengthfirst_line-start.column)inletlast_line=String.sublast_line0end_.columninString.concat"\n"([first_line]@stripped@[last_line])(* Imagine a docstring that is within a file with four characters # of indentation. (I'll
use square brackets rather than parens to avoid escaping):
####[** foo
####
####bar
####
####baz *]
####val x : int
####val y : int
According to odoc, the "b" in "bar" is at column 0 inside the docstring and at column 4
within the broader file. That is correct. But it says the "f" in "foo" is at column 1
inside the docstring and column 5 within the file. This isn't right.
The problem is that it starts counting the inside-the-docstring column number from the
end of "[**", but doesn't add those three characters to the within-the-file column
number. Here, we make the adjustment.
*)letaccount_for_docstring_open_token(location:Odoc_model.Location_.span)=letstart_shift=3inletend_shift=iflocation.start.line=location.end_.linethen3else0in{locationwithstart={location.startwithcolumn=location.start.column+start_shift};end_={location.end_withcolumn=location.end_.column+end_shift};}letextract_code_blocks~(location:Lexing.position)~docstring=letrecaccblocks=List.map(funblock->matchOdoc_model.Location_.valueblockwith|`Code_blockcontents->letlocation=iflocation.pos_lnum=block.location.start.linethenaccount_for_docstring_open_tokenblock.locationelseblock.locationin[{Code_block.location;contents}]|`List(_,_,lists)->List.mapacclists|>List.concat|_->[])blocks|>List.concatinletparsed=Odoc_parser.parse_comment_raw~location~text:docstringinList.iter(funerror->failwith(Odoc_model.Error.to_stringerror))parsed.warnings;List.map(funelement->matchOdoc_model.Location_.valueelementwith|#Odoc_parser.Ast.nestable_block_elementase->acc[{Odoc_model.Location_.location=element.location;value=e}]|`Tagtag->(matchtagwith|`Deprecatedblocks->accblocks|`Param(_,blocks)->accblocks|`Raise(_,blocks)->accblocks|`Returnblocks->accblocks|`See(_,_,blocks)->accblocks|`Before(_,blocks)->accblocks|_->[])|`Heading_->[])parsed.value|>List.concatletdocstringslexbuf=letreclooplist=matchLexer.token_with_commentslexbufwith|Parser.EOF->list|Parser.DOCSTRINGdocstring->letdocstring=(Docstrings.docstring_bodydocstring,Docstrings.docstring_locdocstring)inloop(docstring::list)|_->looplistinloop[]|>List.revletconvert_pos(p:Lexing.position)(pt:Odoc_model.Location_.point)={pwithpos_lnum=pt.line;pos_cnum=pt.column}letconvert_loc(loc:Location.t)(sp:Odoc_model.Location_.span)=letloc_start=convert_posloc.loc_startsp.startinletloc_end=convert_posloc.loc_endsp.end_in{locwithloc_start;loc_end}letdocstring_code_blocksstr=Lexer.handle_docstrings:=true;Lexer.init();List.map(fun(docstring,(location:Location.t))->letblocks=extract_code_blocks~location:location.loc_start~docstringinList.map(fun(b:Code_block.t)->(b,convert_loclocationb.location))blocks)(docstrings(Lexing.from_stringstr))|>List.concatletparse_mlifile_contents=(* Find the locations of the code blocks within [file_contents], then slice it up into
[Text] and [Block] parts by using the starts and ends of those blocks as
boundaries. *)letcode_blocks=docstring_code_blocksfile_contentsinletcursor=ref{Odoc_model.Location_.line=1;column=0}inletlines=String.split_on_char'\n'file_contents|>Array.of_listinlettokens=List.map(fun((code_block:Code_block.t),loc)->letpre_text=Document.Text(slicelines~start:!cursor~end_:code_block.location.start)inletcolumn=code_block.location.start.columninletcontents=Compat.String.split_on_char'\n'code_block.contentsinletblock=matchBlock.mk~loc~section:None~labels:[]~header:(SomeOCaml)~contents~legacy_labels:false~errors:[]with|Okblock->Document.Blockblock|Error_->failwith"Error creating block"inlethpad=ifList.lengthcontents=1then""elseAstring.String.v~len:column(fun_->' ')incursor:=code_block.location.end_;[pre_text;Text"{[";block;Text(hpad^"]}")])code_blocks|>List.concatinleteof={Odoc_model.Location_.line=Array.lengthlines;column=String.lengthlines.(Array.lengthlines-1);}inleteof_is_beyond_location(loc:Odoc_model.Location_.point)=eof.line>loc.line||(eof.line=loc.line&&eof.column>loc.column)inifeof_is_beyond_location!cursorthenletremainder=slicelines~start:!cursor~end_:eofinifnot(Compat.String.equalremainder"")thentokens@[Textremainder]elsetokenselsetokensletparse_mlifile_contents=tryResult.Ok(parse_mlifile_contents)withexn->Util.Result.errorf"%s"(Printexc.to_stringexn)