• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ocaml / odoc / 3283

23 Jul 2026 03:59PM UTC coverage: 70.503%. First build
3283

Pull #1467

github

web-flow
Merge f7bd5c194 into 17e9ae9da
Pull Request #1467: OxCaml: support for kind abbreviations

11 of 109 new or added lines in 17 files covered. (10.09%)

10462 of 14839 relevant lines covered (70.5%)

5822.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.43
/src/model/reference.ml
1
type path = [ `Root of string | `Dot of path * string ]
2

3
let expected_err :
4
    (Format.formatter -> 'a -> unit) -> 'a -> Location_.span -> Error.t =
5
 fun pp_a a -> Error.make "Expected %a." pp_a a
151✔
6

7
let expected_err_str : string -> Location_.span -> Error.t =
8
  expected_err Format.pp_print_string
1,354✔
9

10
let unknown_reference_qualifier : string -> Location_.span -> Error.t =
11
  Error.make "Unknown reference qualifier '%s'."
1,354✔
12

13
let deprecated_reference_kind : string -> string -> Location_.span -> Error.t =
14
  Error.make "'%s' is deprecated, use '%s' instead."
1,354✔
15

16
let reference_kinds_do_not_match : string -> string -> Location_.span -> Error.t
17
    =
18
  Error.make "Old-style reference kind ('%s:') does not match new ('%s-')."
1,354✔
19

20
let should_not_be_empty : what:string -> Location_.span -> Error.t =
21
 fun ~what ->
22
  Error.make "%s should not be empty." (Astring.String.Ascii.capitalize what)
34✔
23

24
let not_allowed :
25
    ?suggestion:string ->
26
    what:string ->
27
    in_what:string ->
28
    Location_.span ->
29
    Error.t =
30
 fun ?suggestion ~what ~in_what ->
31
  Error.make ?suggestion "%s is not allowed in %s."
2✔
32
    (Astring.String.Ascii.capitalize what)
2✔
33
    in_what
34

35
(** Format a list in a human readable way: [A, B, or C]. *)
36
let pp_hum_comma_separated pp_a ppf lst =
37
  let rec loop hd = function
149✔
38
    | [] -> Format.fprintf ppf "or %a" pp_a hd
149✔
39
    | hd' :: tl' ->
483✔
40
        Format.fprintf ppf "%a, " pp_a hd;
41
        loop hd' tl'
483✔
42
  in
43
  match lst with [] -> () | [ a ] -> pp_a ppf a | hd :: tl -> loop hd tl
×
44

45
let deprecated_reference_kind location kind replacement =
46
  deprecated_reference_kind kind replacement location |> Error.raise_warning
8✔
47

48
(* http://caml.inria.fr/pub/docs/manual-ocaml/ocamldoc.html#sec359. *)
49
let match_ocamldoc_reference_kind (_location as loc) s :
50
    [> Paths.Reference.tag_any ] option =
51
  let d = deprecated_reference_kind in
564✔
52
  match s with
53
  | "module" -> Some `TModule
80✔
54
  | "modtype" ->
1✔
55
      d loc "modtype" "module-type";
56
      Some `TModuleType
1✔
57
  | "class" -> Some `TClass
47✔
58
  | "classtype" ->
1✔
59
      d loc "classtype" "class-type";
60
      Some `TClassType
1✔
61
  | "val" -> Some `TValue
27✔
62
  | "type" -> Some `TType
40✔
63
  | "exception" -> Some `TException
17✔
64
  | "attribute" -> None
×
65
  | "method" -> Some `TMethod
47✔
66
  | "section" -> Some `TLabel
34✔
67
  | "const" ->
1✔
68
      d loc "const" "constructor";
69
      Some `TConstructor
1✔
70
  | "recfield" ->
1✔
71
      d loc "recfield" "field";
72
      Some `TField
1✔
73
  | "childpage" -> Some `TChildPage
3✔
74
  | "childmodule" -> Some `TChildModule
5✔
75
  | _ -> None
260✔
76

77
let match_extra_odoc_reference_kind (_location as loc) s :
78
    [> Paths.Reference.tag_any ] option =
79
  let d = deprecated_reference_kind in
260✔
80
  match s with
81
  | "class-type" -> Some `TClassType
19✔
82
  | "constructor" -> Some `TConstructor
56✔
83
  | "exn" ->
1✔
84
      d loc "exn" "exception";
85
      Some `TException
1✔
86
  | "extension" -> Some `TExtension
19✔
87
  | "extension-decl" -> Some `TExtensionDecl
4✔
88
  | "field" -> Some `TField
55✔
89
  | "instance-variable" -> Some `TInstanceVariable
15✔
NEW
90
  | "kind" -> Some `TKindAbbreviation
×
91
  | "label" ->
1✔
92
      d loc "label" "section";
93
      Some `TLabel
1✔
94
  | "module-type" -> Some `TModuleType
33✔
95
  | "page" -> Some `TPage
44✔
96
  | "asset" -> Some `TAsset
3✔
97
  | "value" ->
2✔
98
      d loc "value" "val";
99
      Some `TValue
2✔
100
  | _ -> None
8✔
101

102
type reference_kind = Paths.Reference.tag_any
103

104
(* Ideally, [tokenize] would call this on every reference kind annotation during
105
   tokenization, when generating the token list. However, that constrains the
106
   phantom tag type to be the same for all tokens in the list (because lists are
107
   homogeneous). So, the parser stores kinds as strings in the token list
108
   instead, and this function is called on each string at the latest possible
109
   time to prevent typing issues.
110

111
   A secondary reason to delay parsing, and store strings in the token list, is
112
   that we need the strings for user-friendly error reporting. *)
113
let match_reference_kind location s : reference_kind =
114
  match s with
1,172✔
115
  | `None -> `TUnknown
608✔
116
  | `Prefixed s | `Old_prefix s -> (
39✔
117
      let result =
118
        match match_ocamldoc_reference_kind location s with
119
        | Some _ as kind -> kind
304✔
120
        | None -> match_extra_odoc_reference_kind location s
260✔
121
      in
122
      match result with
123
      | Some kind -> kind
556✔
124
      | None -> unknown_reference_qualifier s location |> Error.raise_exception)
8✔
125

126
type token = {
127
  kind : [ `None | `Prefixed of string ];
128
  identifier : string;
129
  location : Location_.span;
130
}
131

132
type path_prefix = Path_prefix of string * Location_.span
133

134
(* The string is scanned right-to-left, because we are interested in right-most
135
   hyphens. The tokens are also returned in right-to-left order, because the
136
   traversals that consume them prefer to look at the deepest identifier
137
   first. *)
138
let tokenize location s : token list * path_prefix option =
139
  let rec scan_identifier started_at open_parenthesis_count index tokens =
718✔
140
    match s.[index] with
5,488✔
141
    | exception Invalid_argument _ ->
416✔
142
        let identifier, location = identifier_ended started_at index in
143
        ({ kind = `None; identifier; location } :: tokens, None)
397✔
144
    | '-' when open_parenthesis_count = 0 ->
538✔
145
        let identifier, location = identifier_ended started_at index in
537✔
146
        scan_kind identifier location index (index - 1) tokens
533✔
147
    | '.' when open_parenthesis_count = 0 ->
198✔
148
        let identifier, location = identifier_ended started_at index in
197✔
149
        scan_identifier index 0 (index - 1)
196✔
150
          ({ kind = `None; identifier; location } :: tokens)
151
    | '/' when open_parenthesis_count = 0 ->
84✔
152
        let identifier, location = identifier_ended started_at index in
84✔
153
        scan_path index ({ kind = `None; identifier; location } :: tokens)
76✔
154
    | ')' ->
9✔
155
        scan_identifier started_at
156
          (open_parenthesis_count + 1)
157
          (index - 1) tokens
158
    | '(' when open_parenthesis_count > 0 ->
9✔
159
        scan_identifier started_at
9✔
160
          (open_parenthesis_count - 1)
161
          (index - 1) tokens
162
    | '"' -> (
18✔
163
        try
164
          scan_identifier started_at 0
16✔
165
            (String.rindex_from s (index - 1) '"' - 1)
17✔
166
            tokens
167
        with _ ->
2✔
168
          Error.raise_exception (Error.make "Unmatched quotation!" location))
2✔
169
    | _ -> scan_identifier started_at open_parenthesis_count (index - 1) tokens
4,218✔
170
  and identifier_ended started_at index =
171
    let offset = index + 1 in
1,234✔
172
    let length = started_at - offset in
173
    let identifier = String.sub s offset length in
174
    let identifier =
1,234✔
175
      Astring.String.cuts ~sep:"\"" identifier
176
      |> List.mapi (fun i s ->
1,234✔
177
             if i mod 2 = 0 then
1,266✔
178
               Astring.String.cuts s ~sep:" " |> String.concat ""
1,250✔
179
             else s)
16✔
180
      |> String.concat ""
1,234✔
181
    in
182
    let location = Location_.in_string s ~offset ~length location in
1,234✔
183

184
    if identifier = "" then
1,234✔
185
      should_not_be_empty ~what:"Identifier in reference" location
186
      |> Error.raise_exception;
×
187

188
    (identifier, location)
1,202✔
189
  and scan_kind identifier identifier_location started_at index tokens =
190
    match s.[index] with
4,238✔
191
    | exception Invalid_argument _ ->
203✔
192
        let kind, location = kind_ended identifier_location started_at index in
193
        ({ kind; identifier; location } :: tokens, None)
203✔
194
    | '.' ->
321✔
195
        let kind, location = kind_ended identifier_location started_at index in
196
        scan_identifier index 0 (index - 1)
321✔
197
          ({ kind; identifier; location } :: tokens)
198
    | '/' ->
9✔
199
        let kind, location = kind_ended identifier_location started_at index in
200
        scan_path index ({ kind; identifier; location } :: tokens)
9✔
201
    | _ ->
3,705✔
202
        scan_kind identifier identifier_location started_at (index - 1) tokens
203
  and kind_ended identifier_location started_at index =
204
    let offset = index + 1 in
533✔
205
    let length = started_at - offset in
206
    let kind = `Prefixed (String.sub s offset length) in
533✔
207
    let location = Location_.in_string s ~offset ~length location in
208
    let location = Location_.span [ location; identifier_location ] in
533✔
209
    (kind, location)
533✔
210
  and scan_path started_at tokens =
211
    let location =
85✔
212
      Location_.in_string s ~offset:0 ~length:(started_at + 1) location
213
    in
214
    (tokens, Some (Path_prefix (String.sub s 0 (started_at + 1), location)))
85✔
215
  in
216

217
  scan_identifier (String.length s) 0 (String.length s - 1) []
718✔
218
  |> fun (toks, p) -> (List.rev toks, p)
685✔
219

220
let expected ?(expect_paths = false) allowed location =
79✔
221
  let unqualified = [ "an unqualified reference" ] in
149✔
222
  let unqualified =
223
    if expect_paths then "a path" :: unqualified else unqualified
70✔
224
  in
225
  let allowed = List.map (Printf.sprintf "'%s-'") allowed @ unqualified in
149✔
226
  expected_err (pp_hum_comma_separated Format.pp_print_string) allowed location
149✔
227

228
let parse_path whole_path_location p =
229
  let segs = Astring.String.cuts ~sep:"/" p in
91✔
230
  let check segs start =
91✔
231
    let _finish =
91✔
232
      List.fold_left
233
        (fun offset seg ->
234
          match seg with
162✔
235
          | "" ->
2✔
236
              let location =
237
                Location_.in_string p ~offset ~length:0 whole_path_location
238
              in
239
              should_not_be_empty ~what:"Identifier in path reference" location
2✔
240
              |> Error.raise_exception
2✔
241
          | seg -> offset + String.length seg + 1)
160✔
242
        start segs
243
    in
244
    ()
89✔
245
  in
246
  match segs with
247
  | "." :: segs ->
14✔
248
      check segs 2;
249
      (`TRelativePath, segs)
14✔
250
  | "" :: "" :: segs ->
27✔
251
      check segs 2;
252
      (`TCurrentPackage, segs)
26✔
253
  | "" :: segs ->
30✔
254
      check segs 1;
255
      (`TAbsolutePath, segs)
30✔
256
  | segs ->
20✔
257
      check segs 0;
258
      (`TRelativePath, segs)
19✔
259

260
let parse_path_prefix (Path_prefix (p, path_location)) identifier
261
    prefix_location =
262
  parse_path (Location_.span [ path_location; prefix_location ]) (p ^ identifier)
84✔
263

264
(* Parse references that do not contain a [/]. Raises errors and warnings. *)
265
let parse whole_reference_location s :
266
    Paths.Reference.t Error.with_errors_and_warnings =
267
  let open Paths.Reference in
718✔
268
  let open Names in
269
  let parse_from_last_component { kind; identifier; location } old_kind tokens
270
      path_prefix =
271
    let rec signature { kind; identifier; location } tokens : Signature.t =
685✔
272
      let kind = match_reference_kind location kind in
119✔
273
      match tokens with
119✔
274
      | [] -> (
96✔
275
          match path_prefix with
276
          | None -> (
96✔
277
              match kind with
278
              | (`TUnknown | `TModule | `TModuleType) as kind ->
5✔
279
                  `Root (identifier, kind)
280
              | _ ->
39✔
281
                  expected ~expect_paths:true
282
                    [ "module"; "module-type" ]
283
                    location
284
                  |> Error.raise_exception)
39✔
285
          | Some p -> (
×
286
              match kind with
287
              | `TUnknown | `TModule ->
×
288
                  `Module_path (parse_path_prefix p identifier location)
×
289
              | _ ->
×
290
                  expected ~expect_paths:true [ "module" ] location
291
                  |> Error.raise_exception))
×
292
      | next_token :: tokens -> (
23✔
293
          match kind with
294
          | `TUnknown ->
3✔
295
              `Dot ((parent next_token tokens :> LabelParent.t), identifier)
2✔
296
          | `TModule ->
4✔
297
              `Module
298
                (signature next_token tokens, ModuleName.make_std identifier)
3✔
299
          | `TModuleType ->
4✔
300
              `ModuleType
301
                (signature next_token tokens, ModuleTypeName.make_std identifier)
3✔
302
          | _ ->
12✔
303
              expected ~expect_paths:true [ "module"; "module-type" ] location
304
              |> Error.raise_exception)
12✔
305
    and parent { kind; identifier; location } tokens : FragmentTypeParent.t =
306
      let kind = match_reference_kind location kind in
101✔
307
      match tokens with
101✔
308
      | [] -> (
52✔
309
          match path_prefix with
310
          | None -> (
52✔
311
              match kind with
312
              | (`TUnknown | `TModule | `TModuleType | `TType) as kind ->
2✔
313
                  `Root (identifier, kind)
314
              | _ ->
27✔
315
                  expected [ "module"; "module-type"; "type" ] location
316
                  |> Error.raise_exception)
27✔
317
          | Some p -> (
×
318
              match kind with
319
              | `TUnknown | `TModule ->
×
320
                  `Module_path (parse_path_prefix p identifier location)
×
321
              | _ ->
×
322
                  expected ~expect_paths:true [ "module" ] location
323
                  |> Error.raise_exception))
×
324
      | next_token :: tokens -> (
49✔
325
          match kind with
326
          | `TUnknown ->
9✔
327
              `Dot ((parent next_token tokens :> LabelParent.t), identifier)
6✔
328
          | `TModule ->
4✔
329
              `Module
330
                (signature next_token tokens, ModuleName.make_std identifier)
3✔
331
          | `TModuleType ->
4✔
332
              `ModuleType
333
                (signature next_token tokens, ModuleTypeName.make_std identifier)
3✔
334
          | `TType ->
6✔
335
              `Type (signature next_token tokens, TypeName.make_std identifier)
4✔
336
          | _ ->
26✔
337
              expected [ "module"; "module-type"; "type" ] location
338
              |> Error.raise_exception)
26✔
339
    in
340

341
    let class_signature { kind; identifier; location } tokens : ClassSignature.t
342
        =
343
      let kind = match_reference_kind location kind in
40✔
344
      match tokens with
40✔
345
      | [] -> (
19✔
346
          match kind with
347
          | (`TUnknown | `TClass | `TClassType) as kind ->
1✔
348
              `Root (identifier, kind)
349
          | _ ->
14✔
350
              expected [ "class"; "class-type" ] location
351
              |> Error.raise_exception)
14✔
352
      | next_token :: tokens -> (
21✔
353
          match kind with
354
          | `TUnknown ->
3✔
355
              `Dot ((parent next_token tokens :> LabelParent.t), identifier)
2✔
356
          | `TClass ->
3✔
357
              `Class (signature next_token tokens, TypeName.make_std identifier)
2✔
358
          | `TClassType ->
3✔
359
              `ClassType
360
                (signature next_token tokens, TypeName.make_std identifier)
2✔
361
          | _ ->
12✔
362
              expected [ "class"; "class-type" ] location
363
              |> Error.raise_exception)
12✔
364
    in
365

366
    let label_parent_path kind path_prefix identifier location =
367
      match kind with
20✔
368
      | `TUnknown ->
19✔
369
          `Any_path (parse_path_prefix path_prefix identifier location)
19✔
370
      | `TModule ->
×
371
          `Module_path (parse_path_prefix path_prefix identifier location)
×
372
      | `TPage -> `Page_path (parse_path_prefix path_prefix identifier location)
1✔
373
      | _ ->
×
374
          expected ~expect_paths:true [ "module"; "page" ] location
375
          |> Error.raise_exception
×
376
    in
377

378
    let any_path kind path_prefix identifier location =
379
      match kind with
65✔
380
      | `TUnknown ->
57✔
381
          `Any_path (parse_path_prefix path_prefix identifier location)
55✔
382
      | `TModule ->
1✔
383
          `Module_path (parse_path_prefix path_prefix identifier location)
1✔
384
      | `TPage -> `Page_path (parse_path_prefix path_prefix identifier location)
3✔
385
      | `TAsset ->
3✔
386
          `Asset_path (parse_path_prefix path_prefix identifier location)
3✔
387
      | _ ->
1✔
388
          expected ~expect_paths:true [ "module"; "page" ] location
389
          |> Error.raise_exception
1✔
390
    in
391

392
    let rec label_parent { kind; identifier; location } tokens : LabelParent.t =
393
      let kind = match_reference_kind location kind in
188✔
394
      match tokens with
187✔
395
      | [] -> (
137✔
396
          match path_prefix with
397
          | None -> (
117✔
398
              match kind with
399
              | ( `TUnknown | `TModule | `TModuleType | `TType | `TClass
2✔
400
                | `TClassType | `TPage ) as kind ->
1✔
401
                  `Root (identifier, kind)
402
              | _ ->
8✔
403
                  expected ~expect_paths:true
404
                    [
405
                      "module";
406
                      "module-type";
407
                      "type";
408
                      "class";
409
                      "class-type";
410
                      "page";
411
                    ]
412
                    location
413
                  |> Error.raise_exception)
8✔
414
          | Some p -> label_parent_path kind p identifier location)
20✔
415
      | next_token :: tokens -> (
50✔
416
          match kind with
417
          | `TUnknown -> `Dot (label_parent next_token tokens, identifier)
25✔
418
          | `TModule ->
3✔
419
              `Module
420
                (signature next_token tokens, ModuleName.make_std identifier)
2✔
421
          | `TModuleType ->
3✔
422
              `ModuleType
423
                (signature next_token tokens, ModuleTypeName.make_std identifier)
2✔
424
          | `TType ->
3✔
425
              `Type (signature next_token tokens, TypeName.make_std identifier)
2✔
426
          | `TClass ->
5✔
427
              `Class (signature next_token tokens, TypeName.make_std identifier)
3✔
428
          | `TClassType ->
1✔
429
              `ClassType
430
                (signature next_token tokens, TypeName.make_std identifier)
1✔
431
          | _ ->
10✔
432
              expected ~expect_paths:true
433
                [ "module"; "module-type"; "type"; "class"; "class-type" ]
434
                location
435
              |> Error.raise_exception)
10✔
436
    in
437

438
    let start_from_last_component { kind; identifier; location } old_kind tokens
439
        =
440
      let new_kind = match_reference_kind location kind in
685✔
441
      let kind =
682✔
442
        match old_kind with
443
        | None -> new_kind
643✔
444
        | Some (old_kind_string, old_kind_location) -> (
39✔
445
            let old_kind =
446
              match_reference_kind old_kind_location
447
                (`Old_prefix old_kind_string)
448
            in
449
            match new_kind with
35✔
450
            | `TUnknown -> old_kind
32✔
451
            | _ ->
3✔
452
                (if old_kind <> new_kind then
453
                   let new_kind_string =
1✔
454
                     match kind with `None -> "" | `Prefixed s -> s
×
455
                   in
456
                   reference_kinds_do_not_match old_kind_string new_kind_string
457
                     whole_reference_location
458
                   |> Error.raise_warning);
1✔
459
                new_kind)
3✔
460
      in
461

462
      match tokens with
463
      | [] -> (
311✔
464
          match path_prefix with
465
          | None -> `Root (identifier, kind)
246✔
466
          | Some p -> any_path kind p identifier location)
65✔
467
      | next_token :: tokens -> (
367✔
468
          match kind with
469
          | `TUnknown -> `Dot (label_parent next_token tokens, identifier)
120✔
470
          | `TModule ->
30✔
471
              `Module
472
                (signature next_token tokens, ModuleName.make_std identifier)
6✔
473
          | `TModuleType ->
5✔
474
              `ModuleType
475
                (signature next_token tokens, ModuleTypeName.make_std identifier)
3✔
476
          | `TType ->
16✔
477
              `Type (signature next_token tokens, TypeName.make_std identifier)
11✔
NEW
478
          | `TKindAbbreviation ->
×
479
              `KindAbbreviation
NEW
480
                (signature next_token tokens, TypeName.make_std identifier)
×
481
          | `TConstructor ->
42✔
482
              `Constructor
483
                (parent next_token tokens, ConstructorName.make_std identifier)
18✔
484
          | `TField ->
44✔
485
              `Field (parent next_token tokens, FieldName.make_std identifier)
13✔
486
          | `TUnboxedField ->
×
487
              `UnboxedField
488
                (parent next_token tokens, UnboxedFieldName.make_std identifier)
×
489
          | `TExtension ->
6✔
490
              `Extension
491
                (signature next_token tokens, ExtensionName.make_std identifier)
4✔
492
          | `TExtensionDecl ->
2✔
493
              `ExtensionDecl
494
                (signature next_token tokens, ExtensionName.make_std identifier)
2✔
495
          | `TException ->
4✔
496
              `Exception
497
                (signature next_token tokens, ExceptionName.make_std identifier)
2✔
498
          | `TValue ->
4✔
499
              `Value (signature next_token tokens, ValueName.make_std identifier)
2✔
500
          | `TClass ->
5✔
501
              `Class (signature next_token tokens, TypeName.make_std identifier)
3✔
502
          | `TClassType ->
4✔
503
              `ClassType
504
                (signature next_token tokens, TypeName.make_std identifier)
2✔
505
          | `TMethod ->
36✔
506
              `Method
507
                ( class_signature next_token tokens,
9✔
508
                  MethodName.make_std identifier )
36✔
509
          | `TInstanceVariable ->
4✔
510
              `InstanceVariable
511
                ( class_signature next_token tokens,
2✔
512
                  InstanceVariableName.make_std identifier )
4✔
513
          | `TLabel ->
19✔
514
              `Label
515
                (label_parent next_token tokens, LabelName.make_std identifier)
19✔
516
          | `TChildPage | `TChildModule ->
×
517
              let suggestion =
518
                Printf.sprintf "'child-%s' should be first." identifier
519
              in
520
              not_allowed ~what:"Child label"
×
521
                ~in_what:"the last component of a reference path" ~suggestion
522
                location
523
              |> Error.raise_exception
×
524
          | `TPage ->
2✔
525
              let suggestion =
526
                Printf.sprintf "Reference pages as '<parent_path>/%s'."
527
                  identifier
528
              in
529
              not_allowed ~what:"Page label"
2✔
530
                ~in_what:"on the right side of a dot" ~suggestion location
531
              |> Error.raise_exception
2✔
532
          | `TAsset ->
×
533
              let suggestion =
534
                Printf.sprintf "Reference assets as '<parent_path>/%s'."
535
                  identifier
536
              in
537
              not_allowed ~what:"Asset label"
×
538
                ~in_what:"on the right side of a dot" ~suggestion location
539
              |> Error.raise_exception)
×
540
    in
541
    start_from_last_component { kind; identifier; location } old_kind tokens
542
  in
543
  Error.catch_errors_and_warnings (fun () ->
544
      let old_kind, s, location =
718✔
545
        let rec find_old_reference_kind_separator index =
546
          if index < 0 then raise Not_found
677✔
547
          else
548
            match s.[index] with
9,624✔
549
            | ':' -> index
41✔
550
            | ')' -> (
15✔
551
                match String.rindex_from s index '(' with
552
                | index -> find_old_reference_kind_separator (index - 1)
15✔
553
                | exception (Not_found as exn) -> raise exn)
×
554
            | _ -> find_old_reference_kind_separator (index - 1)
9,568✔
555
        in
556
        match find_old_reference_kind_separator (String.length s - 1) with
718✔
557
        | index ->
41✔
558
            let old_kind = String.trim (String.sub s 0 index) in
41✔
559
            let old_kind_location =
41✔
560
              Location_.set_end_as_offset_from_start index
561
                whole_reference_location
562
            in
563
            let s = String.sub s (index + 1) (String.length s - (index + 1)) in
41✔
564
            let location =
41✔
565
              Location_.nudge_start (index + 1) whole_reference_location
566
            in
567
            (Some (old_kind, old_kind_location), s, location)
41✔
568
        | exception Not_found -> (None, s, whole_reference_location)
677✔
569
      in
570
      match tokenize location s with
571
      | last_token :: tokens, path_prefix ->
685✔
572
          parse_from_last_component last_token old_kind tokens path_prefix
573
      | [], _ ->
×
574
          should_not_be_empty ~what:"Reference target" whole_reference_location
575
          |> Error.raise_exception)
×
576

577
(* Parse references that do not contain a [/]. Raises errors and warnings. *)
578
let parse_asset whole_reference_location s :
579
    Paths.Reference.Asset.t Error.with_errors_and_warnings =
580
  let path = parse_path whole_reference_location s in
7✔
581
  Error.catch_errors_and_warnings (fun () -> `Asset_path path)
7✔
582

583
let read_path_longident location s =
584
  let rec loop : string -> int -> path option =
160✔
585
   fun s pos ->
586
    try
335✔
587
      let idx = String.rindex_from s pos '.' in
588
      let name = String.sub s (idx + 1) (pos - idx) in
176✔
589
      if String.length name = 0 then None
1✔
590
      else
591
        match loop s (idx - 1) with
175✔
592
        | None -> None
1✔
593
        | Some parent -> Some (`Dot (parent, name))
174✔
594
    with Not_found ->
159✔
595
      let name = String.sub s 0 (pos + 1) in
596
      if String.length name = 0 then None else Some (`Root name)
1✔
597
  in
598
  Error.catch_warnings (fun () ->
599
      match loop s (String.length s - 1) with
160✔
600
      | Some r -> Ok (r :> path)
158✔
601
      | None -> Error (expected_err_str "a valid path" location))
2✔
602

603
let read_mod_longident location lid =
604
  Error.catch_warnings (fun () ->
30✔
605
      match Error.raise_warnings (parse location lid) with
30✔
606
      | Error _ as e -> e
×
607
      | Ok p -> (
30✔
608
          match p with
609
          | (`Root (_, (`TUnknown | `TModule)) | `Dot (_, _) | `Module (_, _))
×
610
            as r ->
611
              Ok r
612
          | _ -> Error (expected_err_str "a reference to a module" location)))
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc