this repo has no description
at main 350 lines 12 kB view raw
1open Result 2module Error = Odoc_model.Error 3 4let read_string parent_definition filename text = 5 let location = 6 let pos = 7 Lexing.{ pos_fname = filename; pos_lnum = 1; pos_cnum = 0; pos_bol = 0 } 8 in 9 Location.{ loc_start = pos; loc_end = pos; loc_ghost = true } 10 in 11 Error.catch_errors_and_warnings (fun () -> 12 Doc_attr.page parent_definition location text) 13 14let corrupted file = 15 Error.raise_exception (Error.filename_only "corrupted" file) 16 17let not_a_typedtree file = 18 Error.raise_exception (Error.filename_only "not a Typedtree" file) 19 20let not_an_implementation file = 21 Error.raise_exception (Error.filename_only "not an implementation" file) 22 23let not_an_interface file = 24 Error.raise_exception (Error.filename_only "not an interface" file) 25 26let wrong_version file = 27 Error.raise_exception (Error.filename_only "wrong OCaml version" file) 28 29let error_msg file (msg : string) = 30 Error.raise_exception (Error.filename_only "%s" msg file) 31 32type make_root = 33 module_name:string -> 34 digest:Digest.t -> 35 (Odoc_model.Root.t, [ `Msg of string ]) result 36 37exception Corrupted 38 39exception Not_an_implementation 40 41exception Not_an_interface 42 43exception Make_root_error of string 44 45let read_cmt_infos source_id ~filename root digest imports () = 46 match Cmt_format.read_cmt filename with 47 | exception Cmi_format.Error _ -> raise Corrupted 48 | cmt_info -> ( 49 match cmt_info.cmt_annots with 50 | Implementation impl -> 51 let shape_infos = 52 Odoc_model.Compat.shape_info_of_cmt_infos cmt_info 53 in 54 Implementation.read_cmt_infos source_id shape_infos impl digest root 55 imports 56 | _ -> raise Not_an_implementation) 57 58let make_compilation_unit ~make_root ~imports ~interface ?sourcefile ~name ~id 59 ?canonical content = 60 let open Odoc_model.Lang.Compilation_unit in 61 let interface, digest = 62 match interface with 63 | Some digest -> (true, digest) 64 | None -> ( 65 match List.assoc name imports with 66 | Some digest -> (false, digest) 67 | None -> raise Corrupted 68 | exception Not_found -> raise Corrupted) 69 in 70 let root = 71 match make_root ~module_name:name ~digest with 72 | Ok root -> root 73 | Error (`Msg m) -> raise (Make_root_error m) 74 in 75 let imports = List.filter (fun (name', _) -> name <> name') imports in 76 let imports = List.map (fun (s, d) -> Import.Unresolved (s, d)) imports in 77 let source = 78 match sourcefile with 79 | Some (Some file, Some digest, build_dir) -> 80 Some { Source.file; digest; build_dir } 81 | _ -> None 82 in 83 let source_loc_jane = 84 match sourcefile with 85 | Some (Some file, _, build_dir) -> 86 Some {Odoc_model.Lang.Source_loc_jane.filename = build_dir ^ "/" ^ file ; line_number = 1} 87 | _ -> None 88 in 89 { 90 id; 91 root; 92 digest; 93 imports; 94 source; 95 interface; 96 hidden = Odoc_model.Names.contains_double_underscore name; 97 content; 98 expansion = None; 99 linked = false; 100 canonical; 101 source_loc = None; 102 source_loc_jane 103 } 104 105let compilation_unit_of_sig ~make_root ~imports ~interface ?sourcefile ~name ~id 106 ?canonical sg = 107 let content = Odoc_model.Lang.Compilation_unit.Module sg in 108 make_compilation_unit ~make_root ~imports ~interface ?sourcefile ~name ~id 109 ?canonical content 110 111#if defined OXCAML 112let unit_name_as_string = Compilation_unit.name_as_string 113let name_to_string = Compilation_unit.Name.to_string 114#else 115let unit_name_as_string x = x 116let name_to_string x = x 117#endif 118 119let read_cmti ~make_root ~parent ~filename ~warnings_tag () = 120 let cmt_info = Cmt_format.read_cmt filename in 121 match cmt_info.cmt_annots with 122 | Interface intf -> ( 123 match cmt_info.cmt_interface_digest with 124 | None -> raise Corrupted 125 | Some digest as interface -> 126 let _ = 127 try Odoc_model.Names.set_unique_ident (Digest.to_hex digest) 128 with _ -> () 129 in 130 let name = cmt_info.cmt_modname |> unit_name_as_string in 131 let sourcefile = 132 ( cmt_info.cmt_sourcefile, 133 cmt_info.cmt_source_digest, 134 cmt_info.cmt_builddir ) 135 in 136 Cmti.cmti_builddir := cmt_info.cmt_builddir; 137 let id, sg, canonical = 138 Cmti.read_interface parent name ~warnings_tag intf 139 in 140#if defined OXCAML 141 let imports = 142 cmt_info.cmt_imports 143 |> Array.map (fun import -> 144 Import_info.name import |> Compilation_unit.Name.to_string, 145 Import_info.crc import) 146 |> Array.to_list 147 in 148#else 149 let imports = cmt_info.cmt_imports in 150#endif 151 compilation_unit_of_sig ~make_root ~imports 152 ~interface ~sourcefile ~name ~id ?canonical sg) 153 | _ -> raise Not_an_interface 154 155let read_cmt ~make_root ~parent ~filename ~warnings_tag () = 156 match Cmt_format.read_cmt filename with 157 | exception Cmi_format.Error (Not_an_interface _) -> 158 raise Not_an_implementation 159 | cmt_info -> ( 160 let name = cmt_info.cmt_modname |> unit_name_as_string in 161 let sourcefile = 162 ( cmt_info.cmt_sourcefile, 163 cmt_info.cmt_source_digest, 164 cmt_info.cmt_builddir ) 165 in 166 let interface = cmt_info.cmt_interface_digest in 167 (match cmt_info.cmt_interface_digest with 168 | None -> ( 169 match cmt_info.cmt_source_digest with 170 | Some x -> ( 171 try Odoc_model.Names.set_unique_ident (Digest.to_hex x) 172 with _ -> ()) 173 | None -> ( try Odoc_model.Names.set_unique_ident name with _ -> ())) 174 | Some digest -> ( 175 try Odoc_model.Names.set_unique_ident (Digest.to_hex digest) 176 with _ -> ())); 177#if defined OXCAML 178 let imports = 179 cmt_info.cmt_imports 180 |> Array.map (fun import -> 181 Import_info.name import |> Compilation_unit.Name.to_string, 182 Import_info.crc import) 183 |> Array.to_list 184 in 185#else 186 let imports = cmt_info.cmt_imports in 187#endif 188 match cmt_info.cmt_annots with 189 | Packed (_, files) -> 190 let id = 191 Odoc_model.Paths.Identifier.Mk.root 192 (parent, Odoc_model.Names.ModuleName.make_std name) 193 in 194 let items = 195 List.map 196 (fun file -> 197 let pref = Misc.chop_extensions file in 198 Astring.String.Ascii.capitalize (Filename.basename pref)) 199 files 200 in 201 let items = List.sort String.compare items in 202 let items = 203 List.map 204 (fun name -> 205 let id = 206 Odoc_model.Paths.Identifier.Mk.module_ 207 (id, Odoc_model.Names.ModuleName.make_std name) 208 in 209 let path = `Root (Odoc_model.Names.ModuleName.make_std name) in 210 { Odoc_model.Lang.Compilation_unit.Packed.id; path }) 211 items 212 in 213 let content = Odoc_model.Lang.Compilation_unit.Pack items in 214 make_compilation_unit ~make_root ~imports ~interface ~sourcefile ~name 215 ~id content 216 | Implementation impl -> 217 Cmt.cmt_builddir := cmt_info.cmt_builddir; 218 Cmti.cmti_builddir := cmt_info.cmt_builddir; 219 let id, sg, canonical = 220 Cmt.read_implementation parent name ~warnings_tag impl 221 in 222 compilation_unit_of_sig ~make_root ~imports ~interface ~sourcefile 223 ~name ~id ?canonical sg 224 | _ -> raise Not_an_implementation) 225 226#if defined OXCAML 227let compilation_unit_of_import_info (info : Import_info.Intf.Nonalias.t option) = 228 match info with 229 | None -> None 230 | Some (Parameter, _) -> None 231 | Some (Normal cu, _) -> Some (cu |> Compilation_unit.full_path_as_string) 232#else 233let compilation_unit_of_import_info info = 234 Option.map snd info 235#endif 236 237#if defined OXCAML 238let cmi_crcs cmi_info = 239 List.map (fun import -> Import_info.name import, Import_info.Intf.info import) 240 (Array.to_list cmi_info.Cmi_format.cmi_crcs) 241#else 242let cmi_crcs cmi_info = cmi_info.Cmi_format.cmi_crcs 243#endif 244 245let read_cmi ~make_root ~parent ~filename ~warnings_tag () = 246 let cmi_info = Cmi_format.read_cmi filename in 247 let cmi_crcs = cmi_crcs cmi_info in 248 match cmi_crcs with 249 | (name, (Some _ as interface)) :: imports when name = cmi_info.cmi_name -> 250 let name = name |> name_to_string in 251 let id, sg = 252 Cmi.read_interface parent name ~warnings_tag 253 (Odoc_model.Compat.signature cmi_info.cmi_sign) 254 in 255#if defined OXCAML 256 let imports = 257 imports 258 |> List.map (fun (name, info_opt) -> 259 name |> Compilation_unit.Name.to_string, 260 compilation_unit_of_import_info info_opt) 261 in 262 let interface = interface |> Option.map snd in 263#endif 264 compilation_unit_of_sig ~make_root ~imports ~interface ~name ~id sg 265 | _ -> raise Corrupted 266 267let read_impl ~make_root ~filename ~source_id () = 268 match Cmt_format.read_cmt filename with 269 | exception Cmi_format.Error (Not_an_interface _) -> 270 raise Not_an_implementation 271 | cmt_info -> ( 272 let name = cmt_info.cmt_modname |> unit_name_as_string in 273 let _sourcefile = 274 ( cmt_info.cmt_sourcefile, 275 cmt_info.cmt_source_digest, 276 cmt_info.cmt_builddir ) 277 in 278 let interface = cmt_info.cmt_interface_digest in 279 let imports = cmt_info.cmt_imports in 280#if defined OXCAML 281 let imports = 282 imports 283 |> Array.map (fun import -> 284 Import_info.name import |> Compilation_unit.Name.to_string, 285 Import_info.crc import) 286 |> Array.to_list 287 in 288#endif 289 match cmt_info.cmt_annots with 290 | Implementation _impl -> 291 let digest = 292 match interface with 293 | Some digest -> digest 294 | None -> ( 295 match List.assoc name imports with 296 | Some digest -> digest 297 | None -> raise Corrupted 298 | exception Not_found -> raise Corrupted) 299 in 300 let () = 301 match source_id with 302 | None -> Odoc_model.Names.set_unique_ident filename 303 | Some source_id -> 304 Odoc_model.Names.set_unique_ident 305 (Odoc_model.Paths.Identifier.fullname source_id 306 |> String.concat "-") 307 in 308 let root = 309 match make_root ~module_name:name ~digest with 310 | Ok root -> root 311 | Error (`Msg m) -> raise (Make_root_error m) 312 in 313 let imports = List.filter (fun (name', _) -> name <> name') imports in 314 let imports = 315 List.map 316 (fun (s, d) -> 317 Odoc_model.Lang.Compilation_unit.Import.Unresolved (s, d)) 318 imports 319 in 320 read_cmt_infos source_id ~filename root digest imports () 321 | _ -> raise Not_an_implementation) 322 323(** Catch errors from reading the object files and some internal errors *) 324let wrap_errors ~filename f = 325 Odoc_model.Error.catch_errors_and_warnings (fun () -> 326 try f () with 327 | Cmi_format.Error (Not_an_interface _) -> not_an_interface filename 328 | Cmt_format.Error (Not_a_typedtree _) -> not_a_typedtree filename 329 | Cmi_format.Error (Wrong_version_interface _) -> wrong_version filename 330 | Cmi_format.Error (Corrupted_interface _) -> corrupted filename 331 | Corrupted -> corrupted filename 332 | Not_an_implementation -> not_an_implementation filename 333 | Not_an_interface -> not_an_interface filename 334 | Make_root_error m -> error_msg filename m) 335 336let read_cmti ~make_root ~parent ~filename ~warnings_tag = 337 wrap_errors ~filename (read_cmti ~make_root ~parent ~filename ~warnings_tag) 338 339let read_cmt ~make_root ~parent ~filename ~warnings_tag = 340 wrap_errors ~filename (read_cmt ~make_root ~parent ~filename ~warnings_tag) 341 342let read_impl ~make_root ~filename ~source_id = 343 wrap_errors ~filename (read_impl ~make_root ~source_id ~filename) 344 345let read_cmi ~make_root ~parent ~filename ~warnings_tag = 346 wrap_errors ~filename (read_cmi ~make_root ~parent ~filename ~warnings_tag) 347 348let read_location = Doc_attr.read_location 349 350let parse_attribute = Doc_attr.parse_attribute