123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471letexpected_err:string->Location_.span->Error.t=Error.make"Expected %s."letunknown_reference_qualifier:string->Location_.span->Error.t=Error.make"Unknown reference qualifier '%s'."letdeprecated_reference_kind:string->string->Location_.span->Error.t=Error.make"'%s' is deprecated, use '%s' instead."letreference_kinds_do_not_match:string->string->Location_.span->Error.t=Error.make"Old-style reference kind ('%s:') does not match new ('%s-')."letshould_not_be_empty:what:string->Location_.span->Error.t=fun~what->Error.make"%s should not be empty."(Astring.String.Ascii.capitalizewhat)letnot_allowed:?suggestion:string->what:string->in_what:string->Location_.span->Error.t=fun?suggestion~what~in_what->Error.make?suggestion"%s is not allowed in %s."(Astring.String.Ascii.capitalizewhat)in_whatletdeprecated_reference_kindlocationkindreplacement=deprecated_reference_kindkindreplacementlocation|>Error.raise_warning(* http://caml.inria.fr/pub/docs/manual-ocaml/ocamldoc.html#sec359. *)letmatch_ocamldoc_reference_kind(_locationasloc)s:Paths.Reference.tag_anyoption=letd=deprecated_reference_kindinmatchswith|Some"module"->Some`TModule|Some"modtype"->dloc"modtype""module-type";Some`TModuleType|Some"class"->Some`TClass|Some"classtype"->dloc"classtype""class-type";Some`TClassType|Some"val"->Some`TValue|Some"type"->Some`TType|Some"exception"->Some`TException|Some"attribute"->None|Some"method"->Some`TMethod|Some"section"->Some`TLabel|Some"const"->dloc"const""constructor";Some`TConstructor|Some"recfield"->dloc"recfield""field";Some`TField|Some"childpage"->Some`TChildPage|Some"childmodule"->Some`TChildModule|_->Noneletmatch_extra_odoc_reference_kind(_locationasloc)s:Paths.Reference.tag_anyoption=letd=deprecated_reference_kindinmatchswith|Some"class-type"->Some`TClassType|Some"constructor"->Some`TConstructor|Some"exn"->dloc"exn""exception";Some`TException|Some"extension"->Some`TExtension|Some"field"->Some`TField|Some"instance-variable"->Some`TInstanceVariable|Some"label"->dloc"label""section";Some`TLabel|Some"module-type"->Some`TModuleType|Some"page"->Some`TPage|Some"value"->dloc"value""val";Some`TValue|_->None(* Ideally, [tokenize] would call this on every reference kind annotation during
tokenization, when generating the token list. However, that constrains the
phantom tag type to be the same for all tokens in the list (because lists are
homogeneous). So, the parser stores kinds as strings in the token list
instead, and this function is called on each string at the latest possible
time to prevent typing issues.
A secondary reason to delay parsing, and store strings in the token list, is
that we need the strings for user-friendly error reporting. *)letmatch_reference_kindlocations:Paths.Reference.tag_any=matchswith|None->`TUnknown|Somesaswrapped->(letresult=matchmatch_ocamldoc_reference_kindlocationwrappedwith|Somekind->Somekind|None->match_extra_odoc_reference_kindlocationwrappedinmatchresultwith|Somekind->kind|None->unknown_reference_qualifierslocation|>Error.raise_exception)(* The string is scanned right-to-left, because we are interested in right-most
hyphens. The tokens are also returned in right-to-left order, because the
traversals that consume them prefer to look at the deepest identifier
first. *)lettokenizelocations=letrecscan_identifierstarted_atopen_parenthesis_countindextokens=matchs.[index]with|exceptionInvalid_argument_->letidentifier,location=identifier_endedstarted_atindexin(None,identifier,location)::tokens|'-'whenopen_parenthesis_count=0->letidentifier,location=identifier_endedstarted_atindexinscan_kindidentifierlocationindex(index-1)tokens|'.'whenopen_parenthesis_count=0->letidentifier,location=identifier_endedstarted_atindexinscan_identifierindex0(index-1)((None,identifier,location)::tokens)|')'->scan_identifierstarted_at(open_parenthesis_count+1)(index-1)tokens|'('whenopen_parenthesis_count>0->scan_identifierstarted_at(open_parenthesis_count-1)(index-1)tokens|'"'->(tryscan_identifierstarted_at0(String.rindex_froms(index-1)'"'-1)tokenswith_->Error.raise_exception(Error.make"Unmatched quotation!"location))|_->scan_identifierstarted_atopen_parenthesis_count(index-1)tokensandidentifier_endedstarted_atindex=letoffset=index+1inletlength=started_at-offsetinletidentifier=String.subsoffsetlengthinletidentifier=Astring.String.cuts~sep:"\""identifier|>List.mapi(funis->ifimod2=0thenAstring.String.cutss~sep:" "|>String.concat""elses)|>String.concat""inletlocation=Location_.in_strings~offset~lengthlocationinifidentifier=""thenshould_not_be_empty~what:"Identifier in reference"location|>Error.raise_exception;(identifier,location)andscan_kindidentifieridentifier_locationstarted_atindextokens=matchs.[index]with|exceptionInvalid_argument_->letkind,location=kind_endedidentifier_locationstarted_atindexin(kind,identifier,location)::tokens|'.'->letkind,location=kind_endedidentifier_locationstarted_atindexinscan_identifierindex0(index-1)((kind,identifier,location)::tokens)|_->scan_kindidentifieridentifier_locationstarted_at(index-1)tokensandkind_endedidentifier_locationstarted_atindex=letoffset=index+1inletlength=started_at-offsetinletkind=Some(String.subsoffsetlength)inletlocation=Location_.in_strings~offset~lengthlocationinletlocation=Location_.span[location;identifier_location]in(kind,location)inscan_identifier(String.lengths)0(String.lengths-1)[]|>List.revletexpectedallowedlocation=letunqualified="or an unqualified reference"inletallowed=matchallowedwith|[one]->Printf.sprintf"'%s-' %s"oneunqualified|_->String.concat", "(List.map(Printf.sprintf"'%s-'")allowed@[unqualified])inexpected_errallowedlocationletparsewhole_reference_locations:Paths.Reference.tError.with_errors_and_warnings=letopenPaths.ReferenceinletopenNamesinletrecsignature(kind,identifier,location)tokens:Signature.t=letkind=match_reference_kindlocationkindinmatchtokenswith|[]->(matchkindwith|(`TUnknown|`TModule|`TModuleType)askind->`Root(identifier,kind)|_->expected["module";"module-type"]location|>Error.raise_exception)|next_token::tokens->(matchkindwith|`TUnknown->`Dot((parentnext_tokentokens:>LabelParent.t),identifier)|`TModule->`Module(signaturenext_tokentokens,ModuleName.make_stdidentifier)|`TModuleType->`ModuleType(signaturenext_tokentokens,ModuleTypeName.make_stdidentifier)|_->expected["module";"module-type"]location|>Error.raise_exception)andparent(kind,identifier,location)tokens:Parent.t=letkind=match_reference_kindlocationkindinmatchtokenswith|[]->(matchkindwith|(`TUnknown|`TModule|`TModuleType|`TType|`TClass|`TClassType)askind->`Root(identifier,kind)|_->expected["module";"module-type";"type";"class";"class-type"]location|>Error.raise_exception)|next_token::tokens->(matchkindwith|`TUnknown->`Dot((parentnext_tokentokens:>LabelParent.t),identifier)|`TModule->`Module(signaturenext_tokentokens,ModuleName.make_stdidentifier)|`TModuleType->`ModuleType(signaturenext_tokentokens,ModuleTypeName.make_stdidentifier)|`TType->`Type(signaturenext_tokentokens,TypeName.make_stdidentifier)|`TClass->`Class(signaturenext_tokentokens,ClassName.make_stdidentifier)|`TClassType->`ClassType(signaturenext_tokentokens,ClassTypeName.make_stdidentifier)|_->expected["module";"module-type";"type";"class";"class-type"]location|>Error.raise_exception)inletclass_signature(kind,identifier,location)tokens:ClassSignature.t=letkind=match_reference_kindlocationkindinmatchtokenswith|[]->(matchkindwith|(`TUnknown|`TClass|`TClassType)askind->`Root(identifier,kind)|_->expected["class";"class-type"]location|>Error.raise_exception)|next_token::tokens->(matchkindwith|`TUnknown->`Dot((parentnext_tokentokens:>LabelParent.t),identifier)|`TClass->`Class(signaturenext_tokentokens,ClassName.make_stdidentifier)|`TClassType->`ClassType(signaturenext_tokentokens,ClassTypeName.make_stdidentifier)|_->expected["class";"class-type"]location|>Error.raise_exception)inletdatatype(kind,identifier,location)tokens:DataType.t=letkind=match_reference_kindlocationkindinmatchtokenswith|[]->(matchkindwith|(`TUnknown|`TType)askind->`Root(identifier,kind)|_->expected["type"]location|>Error.raise_exception)|next_token::tokens->(matchkindwith|`TUnknown->`Dot((parentnext_tokentokens:>LabelParent.t),identifier)|`TType->`Type(signaturenext_tokentokens,TypeName.make_stdidentifier)|_->expected["type"]location|>Error.raise_exception)inletreclabel_parent(kind,identifier,location)tokens:LabelParent.t=letkind=match_reference_kindlocationkindinmatchtokenswith|[]->(matchkindwith|(`TUnknown|`TModule|`TModuleType|`TType|`TClass|`TClassType|`TPage)askind->`Root(identifier,kind)|_->expected["module";"module-type";"type";"class";"class-type";"page"]location|>Error.raise_exception)|next_token::tokens->(matchkindwith|`TUnknown->`Dot(label_parentnext_tokentokens,identifier)|`TModule->`Module(signaturenext_tokentokens,ModuleName.make_stdidentifier)|`TModuleType->`ModuleType(signaturenext_tokentokens,ModuleTypeName.make_stdidentifier)|`TType->`Type(signaturenext_tokentokens,TypeName.make_stdidentifier)|`TClass->`Class(signaturenext_tokentokens,ClassName.make_stdidentifier)|`TClassType->`ClassType(signaturenext_tokentokens,ClassTypeName.make_stdidentifier)|_->expected["module";"module-type";"type";"class";"class-type"]location|>Error.raise_exception)inletstart_from_last_component(kind,identifier,location)old_kindtokens=letnew_kind=match_reference_kindlocationkindinletkind=matchold_kindwith|None->new_kind|Some(old_kind_string,old_kind_location)->(letold_kind=match_reference_kindold_kind_location(Someold_kind_string)inmatchnew_kindwith|`TUnknown->old_kind|_->(ifold_kind<>new_kindthenletnew_kind_string=matchkindwithSomes->s|None->""inreference_kinds_do_not_matchold_kind_stringnew_kind_stringwhole_reference_location|>Error.raise_warning);new_kind)inmatchtokenswith|[]->`Root(identifier,kind)|next_token::tokens->(matchkindwith|`TUnknown->`Dot(label_parentnext_tokentokens,identifier)|`TModule->`Module(signaturenext_tokentokens,ModuleName.make_stdidentifier)|`TModuleType->`ModuleType(signaturenext_tokentokens,ModuleTypeName.make_stdidentifier)|`TType->`Type(signaturenext_tokentokens,TypeName.make_stdidentifier)|`TConstructor->`Constructor(datatypenext_tokentokens,ConstructorName.make_stdidentifier)|`TField->`Field(parentnext_tokentokens,FieldName.make_stdidentifier)|`TExtension->`Extension(signaturenext_tokentokens,ExtensionName.make_stdidentifier)|`TException->`Exception(signaturenext_tokentokens,ExceptionName.make_stdidentifier)|`TValue->`Value(signaturenext_tokentokens,ValueName.make_stdidentifier)|`TClass->`Class(signaturenext_tokentokens,ClassName.make_stdidentifier)|`TClassType->`ClassType(signaturenext_tokentokens,ClassTypeName.make_stdidentifier)|`TMethod->`Method(class_signaturenext_tokentokens,MethodName.make_stdidentifier)|`TInstanceVariable->`InstanceVariable(class_signaturenext_tokentokens,InstanceVariableName.make_stdidentifier)|`TLabel->`Label(label_parentnext_tokentokens,LabelName.make_stdidentifier)|`TChildPage|`TChildModule->letsuggestion=Printf.sprintf"'child-%s' should be first."identifierinnot_allowed~what:"Child label"~in_what:"the last component of a reference path"~suggestionlocation|>Error.raise_exception|`TPage->letsuggestion=Printf.sprintf"'page-%s' should be first."identifierinnot_allowed~what:"Page label"~in_what:"the last component of a reference path"~suggestionlocation|>Error.raise_exception)inletold_kind,s,location=letrecfind_old_reference_kind_separatorindex=matchs.[index]with|':'->index|')'->(matchString.rindex_fromsindex'('with|index->find_old_reference_kind_separator(index-1)|exception(Not_foundasexn)->raiseexn)|_->find_old_reference_kind_separator(index-1)|exceptionInvalid_argument_->raiseNot_foundinmatchfind_old_reference_kind_separator(String.lengths-1)with|index->letold_kind=String.trim(String.subs0index)inletold_kind_location=Location_.set_end_as_offset_from_startindexwhole_reference_locationinlets=String.subs(index+1)(String.lengths-(index+1))inletlocation=Location_.nudge_start(index+1)whole_reference_locationin(Some(old_kind,old_kind_location),s,location)|exceptionNot_found->(None,s,whole_reference_location)inError.catch_errors_and_warnings(fun()->matchtokenizelocationswith|last_token::tokens->start_from_last_componentlast_tokenold_kindtokens|[]->should_not_be_empty~what:"Reference target"whole_reference_location|>Error.raise_exception)typepath=[`Rootofstring|`DotofPaths.Path.Module.t*string]letread_path_longidentlocations=letopenPaths.Pathinletrecloop:string->int->pathoption=funspos->tryletidx=String.rindex_fromspos'.'inletname=String.subs(idx+1)(pos-idx)inifString.lengthname=0thenNoneelsematchloops(idx-1)with|None->None|Someparent->Some(`Dot((parent:>Module.t),name))withNot_found->letname=String.subs0(pos+1)inifString.lengthname=0thenNoneelseSome(`Rootname)inError.catch_warnings(fun()->matchloops(String.lengths-1)with|Somer->Result.Ok(r:>path)|None->Result.Error(expected_err"a valid path"location))letread_mod_longidentlocationlid=Error.catch_warnings(fun()->matchError.raise_warnings(parselocationlid)with|Error_ase->e|Okp->(matchpwith|(`Root(_,(`TUnknown|`TModule))|`Dot(_,_)|`Module(_,_))asr->Result.Okr|_->Result.Error(expected_err"a reference to a module"location)))