123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280(*
* Copyright (c) 2014 Leo White <lpw25@cl.cam.ac.uk>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)openOdoc_modelmodulePaths=Odoc_model.Pathsletpoint_of_pos{Lexing.pos_lnum;pos_bol;pos_cnum;_}=letcolumn=pos_cnum -pos_bolin{Odoc_model.Location_.line=pos_lnum;column}letread_location{Location.loc_start;loc_end;_}={Odoc_model.Location_.file=loc_start.pos_fname;start=point_of_posloc_start;end_=point_of_posloc_end;}letempty_bodywarnings_tag={Comment.elements=[];warnings_tag}letemptywarnings_tag:Odoc_model.Comment.docs=empty_bodywarnings_tagletload_constant_string=function|{Parsetree.pexp_desc=#ifOCAML_VERSION<(4,3,0)Pexp_constant(Const_string(text,_))#elifOCAML_VERSION<(4,11,0)Pexp_constant(Pconst_string(text,_))#elifOCAML_VERSION<(5,3,0)Pexp_constant(Pconst_string(text,_,_))#elsePexp_constant{pconst_desc=Pconst_string(text,_,_);_}#endif;pexp_loc=loc;_}->Some(text,loc)|_->Noneletload_payload=function|Parsetree.PStr[{pstr_desc =Pstr_eval(constant_string,_);_}]->load_constant_stringconstant_string|_->Noneletload_alert_namename=(Longident.lastname.Location.txt)letload_alert_name_and_payload =function|Parsetree.PStr[{pstr_desc=Pstr_eval({pexp_desc=expression;_},_);_}]->(matchexpressionwith|Pexp_apply({pexp_desc=Pexp_identname;_},[(_,payload)])->Some(load_alert_namename,load_constant_stringpayload)|Pexp_identname->Some(load_alert_namename,None)|_->None)|_->None#ifOCAML_VERSION>=(4,8,0)letattribute_unpack=function|{Parsetree.attr_name={Location.txt=name;_};attr_payload;attr_loc}->(name,attr_payload,attr_loc)#elseletattribute_unpack=function|{Location.txt=name;loc},attr_payload->(name,attr_payload,loc)#endiftypepayload=string*Location.ttypeparsed_attribute=[`Textofpayload(* Standalone comment. *)|`Docofpayload(* Attached comment. *)|`Stopof Location.t(* [(**/**)]. *)|`Alert ofstring*payloadoption*Location.t(* [`Alert (name, payload, loc)] is for [\[@@alert name "payload"\]] attributes. *)](** Recognize an attribute. *)letparse_attribute:Parsetree.attribute->parsed_attributeoption=funattr->letname,attr_payload,attr_loc=attribute_unpackattrinmatchnamewith|"text"|"ocaml.text"->(matchload_payload attr_payloadwith|Some("/*",_)->Some(`Stopattr_loc)|Somep->Some(`Textp)|None->None)|"doc"|"ocaml.doc"->((* We don't expect a stop-comment here. *)matchload_payloadattr_payloadwith|Somep->Some(`Docp)|None->None)|"deprecated"|"ocaml.deprecated" ->Some(`Alert("deprecated",(load_payloadattr_payload),attr_loc))|"alert"|"ocaml.alert"->(matchload_alert_name_and_payloadattr_payloadwithSome(name,payload)->Some(`Alert(name,payload,attr_loc))|None->None)|_->Noneletis_stop_commentattr=matchparse_attribute attr withSome(`Stop_)->true|_->falseletpad_loc loc={loc.Location.loc_startwithpos_cnum=loc.loc_start.pos_cnum+3}letast_to_comment~internal_tagsparentast_docsalerts=Odoc_model.Semantics.ast_to_comment~internal_tags~tags_allowed:true~parent_of_sections:parentast_docsalerts|>Error.raise_warningsletmk_alert_payload~locnamep=letp=matchpwithSome(p,_)->Somep|None->Noneinletelt=`Tag(`Alert(name,p))inlet span=read_locationlocinLocation_.atspaneltletattached~warnings_taginternal_tagsparentattrs=letrecloopacc_docsacc_alerts=function|attr::rest->(matchparse_attributeattrwith|Some(`Doc (str,loc))->letast_docs=Odoc_parser.parse_comment~location:(pad_locloc)~text:str|>Error.raise_parser_warningsinloop(List.rev_appendast_docsacc_docs)acc_alertsrest|Some(`Alert(name,p,loc))->letelt=mk_alert_payload~locnamepinloopacc_docs(elt::acc_alerts)rest|Some (`Text_|`Stop_)|None->loopacc_docsacc_alertsrest)|[]->(List.revacc_docs,List.revacc_alerts)inletast_docs,alerts=loop[][]attrsinletelements,warnings=ast_to_comment~internal_tagsparentast_docsalertsin{Comment.elements;warnings_tag },warningsletattached_no_tag~warnings_tagparentattrs=letx,()=attached ~warnings_tagSemantics.Expect_noneparentattrsinxletread_string~tags_allowedinternal_tagsparent locationstr=Odoc_model.Semantics.parse_comment~internal_tags~tags_allowed~containing_definition:parent~location~text:str|>Odoc_model.Error.raise_warningsletread_string_commentinternal_tagsparent locstr=read_string~tags_allowed:trueinternal_tagsparent(pad_loc loc)strletpageparentlocstr=letelements,tags=read_string~tags_allowed:false Odoc_model.Semantics.Expect_page_tagsparentloc.Location.loc_startstrin{Comment.elements;warnings_tag=None},tagsletstandaloneparent~warnings_tag(attr:Parsetree.attribute):Odoc_model.Comment.docs_or_stop option=matchparse_attributeattrwith|Some(`Stop_loc)->Some`Stop|Some(`Text(str,loc))->letelements,()=read_string_commentSemantics.Expect_noneparentlocstrinSome(`Docs{elements;warnings_tag})|Some(`Doc_)->None|Some(`Alert(name,_,attr_loc))->letw=Error.make"Alert %s not expected here."name(read_locationattr_loc)inError.raise_warningw;None|_->Noneletstandalone_multipleparent~warnings_tag attrs=letcoms=List.fold_left(funaccattr->matchstandaloneparent~warnings_tag attrwith|None->acc|Somecom->com::acc)[]attrsinList.revcomsletsplit_docsdocs=let recinnerfirstx=matchxwith|{Location_.value=`Heading_;_}::_->List.revfirst,x|x::y->inner(x::first)y|[]->List.revfirst,[]ininner[]docsletextract_top_commentinternal_tags~warnings_tag~classifyparentitems=letclassifyx=matchclassifyxwith|Some(`Attributeattr)->(matchparse_attributeattrwith|Some(`Text_as p)->p|Some(`Doc_)->`Skip(* Unexpected, silently ignore *)|Some(`Alert(name,p,attr_loc))->letp=matchpwithSome(p,_)->Somep|None->Noneinletattr_loc=read_locationattr_locin`Alert(Location_.atattr_loc(`Tag(`Alert(name,p))))|Some(`Stop_)->`Return(* Stop at stop-comments. *)|None->`Skip(* Skip unrecognized attributes. *))|Some`Open->`Skip(* Skip open statements *)|None->`Returninletrecextract_tail_alertsacc=function(* Accumulate the alerts after the top-comment. Stop at the next comment. *)|hd::tlasitems->(matchclassifyhdwith|`Text_|`Return->(items,acc)|`Alertalert->extract_tail_alerts(alert::acc)tl|`Skip->extract_tail_alertsacctl)|[]->([],acc)andextract=function(* Extract the first comment and accumulate the alerts before and after
it. *)|hd::tlasitems->(matchclassifyhd with|`Text(text,loc)->letast_docs=Odoc_parser.parse_comment ~location:(pad_locloc)~text|>Error.raise_parser_warningsinletitems,alerts=extract_tail_alerts[]tlin(items,ast_docs,alerts)|`Alertalert->letitems,ast_docs,alerts=extracttlin(items,ast_docs,alert ::alerts)|`Skip->letitems,ast_docs,alerts =extracttlin(hd::items,ast_docs,alerts)|`Return->(items,[],[]))|[]->([],[],[])inletitems,ast_docs,alerts=extractitemsinletdocs,tags=ast_to_comment~internal_tags(parent :Paths.Identifier.Signature.t:>Paths.Identifier.LabelParent.t)ast_docsalertsinletd1,d2=split_docsdocsin(items,({Comment.elements=d1;warnings_tag },{Comment.elements=d2;warnings_tag}),tags)let extract_top_comment_classitems=letmkelementswarnings_tag={Comment.elements;warnings_tag}inmatchitemswith|Lang.ClassSignature.Comment(`Docsdoc)::tl->letd1,d2=split_docsdoc.elementsin(tl,(mkd1doc.warnings_tag,mkd2doc.warnings_tag))|_->(items,(mk[]None,mk[]None))letrecconv_canonical_module :Odoc_model.Reference.path->Paths.Path.Module.t=function|`Dot(parent,name)->`Dot(conv_canonical_moduleparent,Names.ModuleName.make_stdname)|`Rootname->`Root(Names.ModuleName.make_std name)letconv_canonical_type:Odoc_model.Reference.path-> Paths.Path.Type.toption=function|`Dot(parent,name)->Some(`DotT(conv_canonical_moduleparent,Names.TypeName.make_stdname))|_->Noneletconv_canonical_module_type:Odoc_model.Reference.path->Paths.Path.ModuleType.toption=function|`Dot(parent,name)->Some(`DotMT(conv_canonical_moduleparent,Names.ModuleTypeName.make_stdname))|_->None