this repo has no description
at main 964 lines 31 kB view raw
1(* A bunch of association lists. Let's hashtbl them up later *) 2open Odoc_model 3open Odoc_model.Names 4open Odoc_model.Paths 5open Odoc_utils 6 7type lookup_unit_result = Forward_reference | Found of Lang.Compilation_unit.t 8 9type path_query = [ `Path of Reference.Hierarchy.t | `Name of string ] 10 11type lookup_error = [ `Not_found ] 12 13type resolver = { 14 open_units : string list; 15 lookup_unit : path_query -> (lookup_unit_result, lookup_error) result; 16 lookup_page : path_query -> (Lang.Page.t, lookup_error) result; 17 lookup_asset : path_query -> (Lang.Asset.t, lookup_error) result; 18 lookup_impl : string -> Lang.Implementation.t option; 19} 20 21type root = 22 | Resolved of (Root.t * Identifier.Module.t * Component.Module.t) 23 | Forward 24 25let unique_id = 26 let i = ref 0 in 27 fun () -> 28 incr i; 29 !i 30 31type lookup_type = 32 | Module of Paths.Identifier.Path.Module.t 33 | ModuleType of Paths.Identifier.Path.ModuleType.t 34 | RootModule of ModuleName.t * [ `Forward | `Resolved of Digest.t ] option 35 | ModuleByName of string * Paths.Identifier.Path.Module.t 36 | FragmentRoot of int 37 38let pp_lookup_type fmt = 39 let fmtrm fmt = function 40 | Some `Forward -> Format.fprintf fmt "Some (Forward)" 41 | Some (`Resolved digest) -> Format.fprintf fmt "Some (Resolved %s)" digest 42 | None -> Format.fprintf fmt "None" 43 in 44 let c = Component.Fmt.default in 45 function 46 | Module r -> 47 Format.fprintf fmt "Module %a" 48 (Component.Fmt.model_identifier c) 49 (r :> Identifier.t) 50 | ModuleType r -> 51 Format.fprintf fmt "ModuleType %a" 52 (Component.Fmt.model_identifier c) 53 (r :> Identifier.t) 54 | RootModule (n, res) -> 55 Format.fprintf fmt "RootModule %a %a" ModuleName.fmt n fmtrm res 56 | ModuleByName (n, r) -> 57 Format.fprintf fmt "ModuleByName %s, %a" n 58 (Component.Fmt.model_identifier c) 59 (r :> Identifier.t) 60 | FragmentRoot i -> Format.fprintf fmt "FragmentRoot %d" i 61 62let pp_lookup_type_list fmt ls = 63 let rec inner fmt = function 64 | [] -> Format.fprintf fmt "" 65 | [ x ] -> Format.fprintf fmt "%a" pp_lookup_type x 66 | x :: ys -> Format.fprintf fmt "%a; %a" pp_lookup_type x inner ys 67 in 68 Format.fprintf fmt "[%a]" inner ls 69 70module LookupTypeSet = Set.Make (struct 71 type t = lookup_type 72 73 let compare = compare 74end) 75 76type recorder = { mutable lookups : LookupTypeSet.t } 77 78module Maps = Paths.Identifier.Maps 79module StringMap = Map.Make (String) 80 81(** Used only to handle shadowing, see {!Elements}. *) 82type kind = 83 | Kind_Module 84 | Kind_ModuleType 85 | Kind_Type 86 | Kind_Value 87 | Kind_Label 88 | Kind_Class 89 | Kind_ClassType 90 | Kind_Constructor 91 | Kind_Exception 92 | Kind_Extension 93 | Kind_Field 94 | Kind_UnboxedField 95 96module ElementsByName : sig 97 type t 98 99 val empty : t 100 101 val add : kind -> string -> [< Component.Element.any ] -> t -> t 102 103 val find_by_name : 104 (Component.Element.any -> 'b option) -> string -> t -> 'b list 105end = struct 106 type elem = { kind : kind; elem : Component.Element.any } 107 108 type t = elem list StringMap.t 109 110 let empty = StringMap.empty 111 112 let add kind name elem t = 113 let elem = (elem :> Component.Element.any) in 114 let tl = 115 try 116 let tl = StringMap.find name t in 117 let not_shadow e = e.kind <> kind in 118 if not (List.for_all not_shadow tl) then List.filter not_shadow tl 119 else tl 120 with Not_found -> [] 121 in 122 StringMap.add name ({ kind; elem } :: tl) t 123 124 let find_by_name f name t = 125 let filter e acc = match f e.elem with Some r -> r :: acc | None -> acc in 126 try List.fold_right filter (StringMap.find name t) [] with Not_found -> [] 127end 128 129module ElementsById : sig 130 type t 131 132 val empty : t 133 134 val add : 135 [< Identifier.t_pv ] Paths.Identifier.id -> 136 [< Component.Element.any ] -> 137 t -> 138 t 139 140 val find_by_id : 141 [< Identifier.t_pv ] Paths.Identifier.id -> 142 t -> 143 Component.Element.any option 144end = struct 145 module IdMap = Identifier.Maps.Any 146 147 type t = Component.Element.any IdMap.t 148 149 let empty = IdMap.empty 150 151 let add identifier element t = 152 IdMap.add (identifier :> Identifier.t) (element :> Component.Element.any) t 153 154 let find_by_id identifier t = 155 try Some (IdMap.find (identifier :> Identifier.t) t) 156 with Not_found -> None 157end 158 159type 'a amb_err = [ `Ambiguous of 'a * 'a list ] 160 161type t = { 162 linking : bool; 163 (* True if this is a linking environment - if not, we only put in modules, 164 module types, types, classes and class types *) 165 id : int; 166 elts : ElementsByName.t; 167 (** Elements mapped by their name. Queried with {!find_by_name}. *) 168 ids : ElementsById.t; 169 (** Elements mapped by their identifier. Queried with {!find_by_id}. *) 170 ambiguous_labels : Component.Element.label amb_err Identifier.Maps.Label.t; 171 ambiguous_unboxed_labels : 172 Component.Element.label amb_err Identifier.Maps.Label.t; 173 [@warning "-unused-field"] 174 resolver : resolver option; 175 recorder : recorder option; 176 warnings_tags : string list; 177 fragmentroot : (int * Component.Signature.t) option; 178} 179 180let should_suppress_warnings env opt = 181 match opt with None -> false | Some x -> not (List.mem x env.warnings_tags) 182(* Suppress warnings unless the tag is in the list *) 183 184let set_warnings_tags env tags = { env with warnings_tags = tags } 185 186let is_linking env = env.linking 187 188let set_resolver t resolver = { t with resolver = Some resolver } 189 190let has_resolver t = match t.resolver with None -> false | _ -> true 191 192let id t = t.id 193 194let with_recorded_lookups env f = 195 let recorder = { lookups = LookupTypeSet.empty } in 196 let env' = { env with recorder = Some recorder } in 197 let restore () = 198 match env.recorder with 199 | Some r -> r.lookups <- LookupTypeSet.union recorder.lookups r.lookups 200 | None -> () 201 in 202 try 203 let result = f env' in 204 restore (); 205 (recorder.lookups, result) 206 with e -> 207 restore (); 208 raise e 209 210let empty = 211 { 212 linking = true; 213 id = 0; 214 elts = ElementsByName.empty; 215 ids = ElementsById.empty; 216 resolver = None; 217 recorder = None; 218 ambiguous_labels = Identifier.Maps.Label.empty; 219 ambiguous_unboxed_labels = Identifier.Maps.Label.empty; 220 warnings_tags = []; 221 fragmentroot = None; 222 } 223 224let add_fragment_root sg env = 225 let id = unique_id () in 226 { env with fragmentroot = Some (id, sg); id } 227 228(** Implements most [add_*] functions. *) 229let add_to_elts kind identifier component env = 230 if not env.linking then 231 assert ( 232 List.mem kind 233 [ Kind_Module; Kind_ModuleType; Kind_Type; Kind_Class; Kind_ClassType ]); 234 let _ = 235 let other = ElementsById.find_by_id identifier env.ids in 236 match other with 237 | Some _ -> 238 (* Format.eprintf "Overriding duplicate env entry: %s\n%!" (Identifier.name identifier); *) 239 () 240 | None -> () 241 in 242 let name = Identifier.name identifier in 243 { 244 env with 245 id = unique_id (); 246 elts = ElementsByName.add kind name component env.elts; 247 ids = ElementsById.add identifier component env.ids; 248 } 249 250let add_label identifier heading env ~unboxed = 251 assert env.linking; 252 (* TODO: implement proper behavior for unboxed labels *) 253 assert (not unboxed); 254 let comp = `Label (identifier, heading) in 255 let name = Identifier.name identifier in 256 let ambiguous_labels = 257 match ElementsById.find_by_id identifier env.ids with 258 | Some (#Component.Element.label as l) -> 259 let err = 260 try 261 match 262 Identifier.Maps.Label.find identifier env.ambiguous_labels 263 with 264 | `Ambiguous (x, others) -> `Ambiguous (x, comp :: others) 265 with Not_found -> `Ambiguous (l, [ comp ]) 266 in 267 268 Identifier.Maps.Label.add identifier err env.ambiguous_labels 269 | Some _ -> assert false 270 | None -> env.ambiguous_labels 271 in 272 { 273 env with 274 id = unique_id (); 275 elts = 276 ElementsByName.add Kind_Label name 277 (comp :> Component.Element.any) 278 env.elts; 279 ambiguous_labels; 280 ids = ElementsById.add identifier comp env.ids; 281 } 282 283let add_docs (docs : Comment.docs) env = 284 assert env.linking; 285 List.fold_left 286 (fun env -> function 287 | { Location_.value = `Heading (attrs, id, text); location } -> 288 let label = Ident.Of_Identifier.label id in 289 add_label id 290 { Component.Label.attrs; label; text; location } 291 env ~unboxed:false 292 | _ -> env) 293 env docs.elements 294 295let add_comment (com : Comment.docs_or_stop) env = 296 match com with `Docs doc -> add_docs doc env | `Stop -> env 297 298let add_cdocs p (docs : Component.CComment.docs) env = 299 List.fold_left 300 (fun env element -> 301 match element.Location_.value with 302 | `Heading h -> 303 let (`LLabel (name, _)) = h.Component.Label.label in 304 let label = 305 Paths.Identifier.Mk.label (Paths.Identifier.label_parent p, name) 306 in 307 add_label label h env ~unboxed:false 308 | _ -> env) 309 env docs.elements 310 311let add_module identifier m docs env = 312 let env' = add_to_elts Kind_Module identifier (`Module (identifier, m)) env in 313 if env.linking then add_cdocs identifier docs env' else env' 314 315let add_type (identifier : Identifier.Type.t) t env = 316 let open Component in 317 let open_typedecl cs = 318 let add_cons env (cons : TypeDecl.Constructor.t) = 319 let ident = 320 Paths.Identifier.Mk.constructor 321 ( (identifier :> Identifier.DataType.t), 322 ConstructorName.make_std cons.name ) 323 in 324 add_to_elts Kind_Constructor ident (`Constructor (ident, cons)) env 325 and add_field env (field : TypeDecl.Field.t) = 326 let ident = 327 Paths.Identifier.Mk.field 328 ( (identifier :> Paths.Identifier.FieldParent.t), 329 FieldName.make_std field.name ) 330 in 331 add_to_elts Kind_Field ident (`Field (ident, field)) env 332 and add_unboxed_field env (field : TypeDecl.UnboxedField.t) = 333 let ident = 334 Paths.Identifier.Mk.unboxed_field 335 ( (identifier :> Paths.Identifier.UnboxedFieldParent.t), 336 UnboxedFieldName.make_std field.name ) 337 in 338 add_to_elts Kind_UnboxedField ident (`UnboxedField (ident, field)) env 339 in 340 let open TypeDecl in 341 match t.representation with 342 | Some (Variant cons) -> 343 ( List.fold_left add_cons cs cons, 344 List.map (fun t -> t.Constructor.doc) cons ) 345 | Some (Record fields) -> 346 ( List.fold_left add_field cs fields, 347 List.map (fun t -> t.Field.doc) fields ) 348 | Some (Record_unboxed_product fields) -> 349 ( List.fold_left add_unboxed_field cs fields, 350 List.map (fun t -> t.UnboxedField.doc) fields ) 351 | Some Extensible | None -> (cs, []) 352 in 353 let env, docs = if env.linking then open_typedecl env else (env, []) in 354 let env = add_to_elts Kind_Type identifier (`Type (identifier, t)) env in 355 if env.linking then 356 add_cdocs identifier t.doc env 357 |> List.fold_right (add_cdocs identifier) docs 358 else env 359 360let add_module_type identifier (t : Component.ModuleType.t) env = 361 let env' = 362 add_to_elts Kind_ModuleType identifier (`ModuleType (identifier, t)) env 363 in 364 if env'.linking then add_cdocs identifier t.doc env' else env' 365 366let add_value identifier (t : Component.Value.t) env = 367 add_to_elts Kind_Value identifier (`Value (identifier, t)) env 368 |> add_cdocs identifier t.doc 369 370let add_class identifier (t : Component.Class.t) env = 371 let env' = add_to_elts Kind_Class identifier (`Class (identifier, t)) env in 372 if env'.linking then add_cdocs identifier t.doc env' else env' 373 374let add_class_type identifier (t : Component.ClassType.t) env = 375 let env' = 376 add_to_elts Kind_ClassType identifier (`ClassType (identifier, t)) env 377 in 378 if env'.linking then add_cdocs identifier t.doc env' else env' 379 380let add_method _identifier _t env = 381 (* TODO *) 382 env 383 384let add_exception identifier (e : Component.Exception.t) env = 385 add_to_elts Kind_Exception identifier (`Exception (identifier, e)) env 386 |> add_cdocs identifier e.doc 387 388let add_extension_constructor identifier 389 (ec : Component.Extension.Constructor.t) te env = 390 add_to_elts Kind_Extension identifier (`Extension (identifier, ec, te)) env 391 |> add_cdocs identifier ec.doc 392 393let module_of_unit : Lang.Compilation_unit.t -> Component.Module.t = 394 fun unit -> 395 let id = (unit.id :> Paths.Identifier.Module.t) in 396 match unit.content with 397 | Module s -> 398 let m = 399 Lang.Module. 400 { 401 id; 402 source_loc = None; 403 source_loc_jane = unit.source_loc_jane; 404 doc = { elements = []; warnings_tag = None }; 405 type_ = ModuleType (Signature s); 406 canonical = unit.canonical; 407 hidden = unit.hidden; 408 } 409 in 410 let ty = Component.Of_Lang.(module_ (empty ()) m) in 411 ty 412 | Pack _p -> 413 let m = 414 Lang.Module. 415 { 416 id; 417 source_loc = None; 418 source_loc_jane = unit.source_loc_jane; 419 doc = { elements = []; warnings_tag = None }; 420 type_ = 421 ModuleType 422 (Signature 423 { 424 items = []; 425 compiled = true; 426 removed = []; 427 doc = { elements = []; warnings_tag = None }; 428 }); 429 canonical = unit.canonical; 430 hidden = unit.hidden; 431 } 432 in 433 let ty = Component.Of_Lang.(module_ (empty ()) m) in 434 ty 435 436let lookup_root_module name env = 437 let result = 438 match env.resolver with 439 | None -> None 440 | Some r -> ( 441 match r.lookup_unit (`Name (ModuleName.to_string name)) with 442 | Ok Forward_reference -> Some Forward 443 | Error `Not_found -> None 444 | Ok (Found u) -> 445 let ({ Odoc_model.Paths.Identifier.iv = `Root _; _ } as id) = 446 u.id 447 in 448 let m = module_of_unit u in 449 Some (Resolved (u.root, id, m))) 450 in 451 (match (env.recorder, result) with 452 | Some r, Some Forward -> 453 r.lookups <- 454 LookupTypeSet.add (RootModule (name, Some `Forward)) r.lookups 455 | Some r, Some (Resolved (root, _, _)) -> 456 r.lookups <- 457 LookupTypeSet.add 458 (RootModule (name, Some (`Resolved root.digest))) 459 r.lookups 460 | Some r, None -> 461 r.lookups <- LookupTypeSet.add (RootModule (name, None)) r.lookups 462 | None, _ -> ()); 463 result 464 465let lookup_page query env = 466 match env.resolver with 467 | None -> Error `Not_found 468 | Some r -> r.lookup_page query 469 470let lookup_asset query env = 471 match env.resolver with 472 | None -> Error `Not_found 473 | Some r -> r.lookup_asset query 474 475let lookup_unit query env = 476 match env.resolver with 477 | None -> Error `Not_found 478 | Some r -> r.lookup_unit query 479 480let lookup_impl name env = 481 match env.resolver with None -> None | Some r -> r.lookup_impl name 482 483let lookup_page_by_name n env = lookup_page (`Name n) env 484let lookup_page_by_path p env = lookup_page (`Path p) env 485 486let lookup_asset_by_name p env = lookup_asset (`Name p) env 487let lookup_asset_by_path p env = lookup_asset (`Path p) env 488 489let lookup_unit_by_path p env = 490 match lookup_unit (`Path p) env with 491 | Ok (Found u) -> 492 let m = Component.Delayed.put_val (module_of_unit u) in 493 Ok (`Module ((u.id :> Identifier.Path.Module.t), m)) 494 | Ok Forward_reference -> Error `Not_found (* TODO: Remove this case *) 495 | Error _ as e -> e 496 497type 'a scope = { 498 filter : Component.Element.any -> ([< Component.Element.any ] as 'a) option; 499 check : (t -> ([< Component.Element.any ] as 'a) -> 'a amb_err option) option; 500 root : string -> t -> 'a option; 501} 502 503type 'a maybe_ambiguous = ('a, [ 'a amb_err | `Not_found ]) result 504 505let make_scope ?(root = fun _ _ -> None) ?check 506 (filter : _ -> ([< Component.Element.any ] as 'a) option) : 'a scope = 507 { filter; check; root } 508 509let lookup_by_name scope name env = 510 let record_lookup_results env results = 511 match env.recorder with 512 | Some r -> 513 List.iter 514 (function 515 | `Module (id, _) -> 516 r.lookups <- 517 LookupTypeSet.add (ModuleByName (name, id)) r.lookups 518 | _ -> ()) 519 (results :> Component.Element.any list) 520 | None -> () 521 in 522 match 523 (ElementsByName.find_by_name scope.filter name env.elts, scope.check) 524 with 525 | ([ x ] as results), Some c -> ( 526 record_lookup_results env results; 527 match c env x with Some (`Ambiguous _ as e) -> Error e | None -> Ok x) 528 | ([ x ] as results), None -> 529 record_lookup_results env results; 530 Ok x 531 | (x :: tl as results), _ -> 532 record_lookup_results env results; 533 Error (`Ambiguous (x, tl)) 534 | [], _ -> ( 535 match scope.root name env with Some x -> Ok x | None -> Error `Not_found) 536 537let lookup_by_id (scope : 'a scope) id env : 'a option = 538 let record_lookup_result result = 539 match env.recorder with 540 | Some r -> ( 541 match (result :> Component.Element.any) with 542 | `Module (id, _) -> 543 r.lookups <- LookupTypeSet.add (Module id) r.lookups 544 | `ModuleType (id, _) -> 545 r.lookups <- LookupTypeSet.add (ModuleType id) r.lookups 546 | _ -> ()) 547 | None -> () 548 in 549 match ElementsById.find_by_id id env.ids with 550 | Some x -> 551 record_lookup_result x; 552 scope.filter x 553 | None -> ( 554 (* Format.eprintf "Can't find %a\n%!" Component.Fmt.model_identifier (id :> Identifier.t); *) 555 match (id :> Identifier.t) with 556 | { iv = `Root (_, name); _ } -> 557 scope.root (ModuleName.to_string name) env 558 | _ -> None) 559 560let lookup_root_module_fallback name t = 561 match lookup_root_module (ModuleName.make_std name) t with 562 | Some (Resolved (_, id, m)) -> 563 Some 564 (`Module ((id :> Identifier.Path.Module.t), Component.Delayed.put_val m)) 565 | Some Forward | None -> None 566 567let lookup_page_or_root_module_fallback name t = 568 match lookup_root_module_fallback name t with 569 | Some _ as x -> x 570 | None -> ( 571 match lookup_page_by_name name t with 572 | Ok page -> Some (`Page (page.Lang.Page.name, page)) 573 | Error `Not_found -> None) 574 575let s_signature : Component.Element.signature scope = 576 make_scope ~root:lookup_root_module_fallback (function 577 | #Component.Element.signature as r -> Some r 578 | _ -> None) 579 580let s_module : Component.Element.module_ scope = 581 make_scope ~root:lookup_root_module_fallback (function 582 | #Component.Element.module_ as r -> Some r 583 | _ -> None) 584 585let s_any : Component.Element.any scope = 586 make_scope ~root:lookup_page_or_root_module_fallback 587 ~check:(fun env -> function 588 | `Label (id, _) -> ( 589 try 590 Some 591 (Identifier.Maps.Label.find id env.ambiguous_labels 592 :> Component.Element.any amb_err) 593 with Not_found -> None) 594 | _ -> None) 595 (function 596 (* Reference to [A] could refer to [extension-A] or [extension-decl-A]. 597 The legacy behavior refers to the constructor [extension-A]. *) 598 | #Component.Element.extension_decl -> None 599 | r -> Some r) 600 601let s_module_type : Component.Element.module_type scope = 602 make_scope (function 603 | #Component.Element.module_type as r -> Some r 604 | _ -> None) 605 606let s_type : Component.Element.type_ scope = 607 make_scope (function #Component.Element.type_ as r -> Some r | _ -> None) 608 609let s_datatype : Component.Element.datatype scope = 610 make_scope (function #Component.Element.datatype as r -> Some r | _ -> None) 611 612let s_class : Component.Element.class_ scope = 613 make_scope (function #Component.Element.class_ as r -> Some r | _ -> None) 614 615let s_class_type : Component.Element.class_type scope = 616 make_scope (function 617 | #Component.Element.class_type as r -> Some r 618 | _ -> None) 619 620let s_value : Component.Element.value scope = 621 make_scope (function #Component.Element.value as r -> Some r | _ -> None) 622 623let s_label : Component.Element.label scope = 624 make_scope 625 ~check:(fun env -> function 626 | `Label (id, _) -> ( 627 try Some (Identifier.Maps.Label.find id env.ambiguous_labels) 628 with Not_found -> None)) 629 (function #Component.Element.label as r -> Some r | _ -> None) 630 631let s_constructor : Component.Element.constructor scope = 632 make_scope (function 633 | #Component.Element.constructor as r -> Some r 634 | _ -> None) 635 636let s_exception : Component.Element.exception_ scope = 637 make_scope (function 638 | #Component.Element.exception_ as r -> Some r 639 | _ -> None) 640 641let s_extension : Component.Element.extension scope = 642 make_scope (function 643 | #Component.Element.extension as r -> Some r 644 | _ -> None) 645 646let s_field : Component.Element.field scope = 647 make_scope (function #Component.Element.field as r -> Some r | _ -> None) 648 649let s_unboxed_field : Component.Element.unboxed_field scope = 650 make_scope (function 651 | #Component.Element.unboxed_field as r -> Some r 652 | _ -> None) 653 654let s_label_parent : Component.Element.label_parent scope = 655 make_scope ~root:lookup_page_or_root_module_fallback (function 656 | #Component.Element.label_parent as r -> Some r 657 | _ -> None) 658 659let s_fragment_type_parent : Component.Element.fragment_type_parent scope = 660 make_scope ~root:lookup_root_module_fallback (function 661 | #Component.Element.fragment_type_parent as r -> Some r 662 | _ -> None) 663 664let len = ref 0 665 666let n = ref 0 667 668let lookup_fragment_root env = 669 let maybe_record_result res = 670 match env.recorder with 671 | Some r -> r.lookups <- LookupTypeSet.add res r.lookups 672 | None -> () 673 in 674 match env.fragmentroot with 675 | Some (i, _) as result -> 676 maybe_record_result (FragmentRoot i); 677 result 678 | None -> None 679 680let mk_functor_parameter module_type = 681 let type_ = Component.Module.ModuleType module_type in 682 Component.Module. 683 { 684 source_loc = None; 685 source_loc_jane = None; 686 doc = { elements = []; warnings_tag = None }; 687 type_; 688 canonical = None; 689 hidden = false; 690 } 691 692let add_functor_parameter : Lang.FunctorParameter.t -> t -> t = 693 fun p t -> 694 match p with 695 | Unit -> t 696 | Named n -> 697 let id = (n.id :> Paths.Identifier.Path.Module.t) in 698 let m = 699 let open Component.Of_Lang in 700 mk_functor_parameter (module_type_expr (empty ()) n.expr) 701 in 702 add_module id 703 (Component.Delayed.put_val m) 704 { elements = []; warnings_tag = None } 705 t 706 707let add_functor_args' : 708 Paths.Identifier.Signature.t -> Component.ModuleType.expr -> t -> t = 709 let open Component in 710 fun id expr env -> 711 let rec find_args parent mty = 712 match mty with 713 | ModuleType.Functor (Named arg, res) -> 714 ( arg.Component.FunctorParameter.id, 715 Paths.Identifier.Mk.parameter 716 (parent, Ident.Name.typed_module arg.Component.FunctorParameter.id), 717 mk_functor_parameter arg.expr ) 718 :: find_args (Paths.Identifier.Mk.result parent) res 719 | ModuleType.Functor (Unit, res) -> 720 find_args (Paths.Identifier.Mk.result parent) res 721 | _ -> [] 722 in 723 (* We substituted back the parameters as identifiers to maintain the 724 invariant that components in the environment are 'self-contained' - that 725 is, they only contain local idents for things that are declared within 726 themselves *) 727 let fold_fn (env, subst) (ident, identifier, m) = 728 let ident, identifier = 729 ((ident, identifier) :> Ident.module_ * Identifier.Path.Module.t) 730 in 731 let doc = m.Component.Module.doc in 732 let m = Component.Delayed.put_val (Subst.module_ subst m) in 733 let rp = `Gpath (`Identifier identifier) in 734 let p = `Resolved rp in 735 let env' = add_module identifier m doc env in 736 (env', Subst.add_module ident p rp subst) 737 in 738 let env', _subst = 739 List.fold_left fold_fn (env, Subst.identity) (find_args id expr) 740 in 741 env' 742 743let add_module_functor_args m id env = 744 match m.Component.Module.type_ with 745 | Alias _ -> env 746 | ModuleType expr -> 747 add_functor_args' (id :> Paths.Identifier.Signature.t) expr env 748 749let add_module_type_functor_args mt id env = 750 match mt.Component.ModuleType.expr with 751 | None -> env 752 | Some expr -> add_functor_args' (id :> Paths.Identifier.Signature.t) expr env 753 754let open_class_signature : Lang.ClassSignature.t -> t -> t = 755 let open Component in 756 let open Of_Lang in 757 fun s env -> 758 List.fold_left 759 (fun env orig -> 760 match orig with 761 | Lang.ClassSignature.Method m -> 762 let ty = method_ (empty ()) m in 763 add_method m.Lang.Method.id ty env 764 | _ -> env) 765 env s.items 766 767let rec open_signature : Lang.Signature.t -> t -> t = 768 let open Component in 769 let open Of_Lang in 770 let module L = Lang in 771 fun s e -> 772 let ident_map = empty () in 773 List.fold_left 774 (fun env orig -> 775 match ((orig : L.Signature.item), env.linking) with 776 | Type (_, t), _ -> 777 let ty = type_decl ident_map t in 778 add_type t.L.TypeDecl.id ty env 779 | Module (_, t), _ -> 780 let ty = Component.Delayed.put (fun () -> module_ ident_map t) in 781 add_module 782 (t.L.Module.id :> Identifier.Path.Module.t) 783 ty 784 (docs ident_map t.L.Module.doc) 785 env 786 | ModuleType t, _ -> 787 let ty = module_type ident_map t in 788 add_module_type t.L.ModuleType.id ty env 789 | ModuleTypeSubstitution _, _ 790 | L.Signature.TypeSubstitution _, _ 791 | L.Signature.ModuleSubstitution _, _ -> 792 env 793 | L.Signature.Class (_, c), _ -> 794 let ty = class_ ident_map c in 795 add_class c.id ty env 796 | L.Signature.ClassType (_, c), _ -> 797 let ty = class_type ident_map c in 798 add_class_type c.id ty env 799 | L.Signature.Include i, _ -> open_signature i.expansion.content env 800 | L.Signature.Open o, false -> open_signature o.expansion env 801 (* The following are only added when linking *) 802 | L.Signature.Open o, true -> 803 add_comment (`Docs o.doc) (open_signature o.expansion env) 804 | Comment c, true -> add_comment c env 805 | TypExt te, true -> 806 let doc = docs ident_map te.doc in 807 let te' = extension ident_map te in 808 List.fold_left 809 (fun env tec -> 810 let ty = extension_constructor ident_map tec in 811 add_extension_constructor tec.L.Extension.Constructor.id ty te' 812 env) 813 env te.L.Extension.constructors 814 |> add_cdocs te.L.Extension.parent doc 815 | Exception e, true -> 816 let ty = exception_ ident_map e in 817 add_exception e.L.Exception.id ty env 818 | L.Signature.Value v, true -> 819 let ty = value ident_map v in 820 add_value v.L.Value.id ty env 821 (* Skip when compiling *) 822 | Exception _, false -> env 823 | TypExt _, false -> env 824 | Comment _, false -> env 825 | L.Signature.Value _, false -> env) 826 e s.items 827 828let open_type_substitution : Odoc_model.Lang.TypeDecl.t -> t -> t = 829 fun t env -> 830 let open Component in 831 let open Of_Lang in 832 let ty = type_decl (empty ()) t in 833 add_type t.Lang.TypeDecl.id ty env 834 835let open_module_substitution : Odoc_model.Lang.ModuleSubstitution.t -> t -> t = 836 fun m env -> 837 let open Component in 838 let open Of_Lang in 839 let _id = Ident.Of_Identifier.module_ m.id in 840 let doc = docs (empty ()) m.doc in 841 let ty = 842 Component.Delayed.put (fun () -> 843 Of_Lang.( 844 module_of_module_substitution 845 (* { empty with modules = [ (m.id, id) ] } *) 846 (empty ()) 847 m)) 848 in 849 add_module (m.id :> Identifier.Path.Module.t) ty doc env 850 851let open_module_type_substitution : Lang.ModuleTypeSubstitution.t -> t -> t = 852 fun t env -> 853 let open Component in 854 let open Of_Lang in 855 let ty = 856 module_type (empty ()) 857 { 858 id = t.id; 859 source_loc = None; 860 source_loc_jane = None; 861 doc = t.doc; 862 expr = Some t.manifest; 863 canonical = None; 864 } 865 in 866 add_module_type t.Lang.ModuleTypeSubstitution.id ty env 867 868let open_units resolver env = 869 List.fold_left 870 (fun env m -> 871 match resolver.lookup_unit (`Name m) with 872 | Ok (Found unit) -> ( 873 match unit.content with 874 | Module sg -> open_signature sg env 875 | _ -> env) 876 | _ -> env) 877 env resolver.open_units 878 879let inherit_resolver env = 880 match env.resolver with 881 | Some r -> 882 let e = set_resolver empty r in 883 open_units r e 884 | None -> empty 885 886let env_of_unit t ~linking resolver = 887 let open Lang.Compilation_unit in 888 let initial_env = 889 let m = module_of_unit t in 890 let dm = Component.Delayed.put (fun () -> m) in 891 let env = { empty with linking } in 892 env |> add_module (t.id :> Identifier.Path.Module.t) dm m.doc 893 in 894 set_resolver initial_env resolver |> open_units resolver 895 896let open_page page env = add_docs page.Lang.Page.content env 897 898let env_of_page page resolver = 899 let initial_env = open_page page empty in 900 set_resolver initial_env resolver |> open_units resolver 901 902let env_of_impl _impl resolver = 903 set_resolver empty resolver |> open_units resolver 904 905let env_for_reference resolver = 906 set_resolver empty resolver |> open_units resolver 907 908let env_for_testing ~linking = { empty with linking } 909 910let verify_lookups env lookups = 911 let bad_lookup = function 912 | Module id -> 913 let actually_found = 914 match lookup_by_id s_module id env with 915 | Some _ -> true 916 | None -> false 917 in 918 true <> actually_found 919 | RootModule (name, res) -> ( 920 let actual_result = 921 match env.resolver with 922 | None -> None 923 | Some r -> ( 924 match r.lookup_unit (`Name (ModuleName.to_string name)) with 925 | Ok Forward_reference -> Some `Forward 926 | Ok (Found u) -> Some (`Resolved u.root.digest) 927 | Error `Not_found -> None) 928 in 929 match (res, actual_result) with 930 | None, None -> false 931 | Some `Forward, Some `Forward -> false 932 | Some (`Resolved digest1), Some (`Resolved digest2) -> 933 digest1 <> digest2 934 | _ -> true) 935 | ModuleType id -> 936 let actually_found = 937 match lookup_by_id s_module_type id env with 938 | Some _ -> true 939 | None -> false 940 in 941 true <> actually_found 942 | ModuleByName (name, result) -> ( 943 match lookup_by_name s_module name env with 944 | Ok (`Module (id', _)) -> result <> id' 945 | Error `Not_found -> false 946 | Error (`Ambiguous (hd, tl)) -> 947 not 948 (List.exists (fun (`Module (id', _)) -> result = id') (hd :: tl))) 949 | FragmentRoot _i -> true 950 (* begin 951 try 952 let (i', _) = Env.lookup_fragment_root env in 953 i' <> i 954 with _ -> 955 true 956 end*) 957 in 958 let result = not (LookupTypeSet.exists bad_lookup lookups) in 959 (* If we're recording lookups, make sure it looks like we 960 looked all this stuff up *) 961 (match (result, env.recorder) with 962 | true, Some r -> r.lookups <- LookupTypeSet.union r.lookups lookups 963 | _ -> ()); 964 result