105 lines
3.4 KiB
Plaintext
105 lines
3.4 KiB
Plaintext
|
/-
|
||
|
Copyright (c) 2022 Henrik Böving. All rights reserved.
|
||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||
|
Authors: Henrik Böving
|
||
|
-/
|
||
|
|
||
|
import Lean
|
||
|
import Std.Data.HashMap
|
||
|
|
||
|
import DocGen4.Process.Base
|
||
|
import DocGen4.Process.Hierarchy
|
||
|
import DocGen4.Process.DocInfo
|
||
|
|
||
|
namespace DocGen4.Process
|
||
|
|
||
|
open Lean Meta Std
|
||
|
|
||
|
inductive ModuleMember where
|
||
|
| docInfo (info : DocInfo) : ModuleMember
|
||
|
| modDoc (doc : ModuleDoc) : ModuleMember
|
||
|
deriving Inhabited
|
||
|
|
||
|
structure Module where
|
||
|
name : Name
|
||
|
-- Sorted according to their line numbers
|
||
|
members : Array ModuleMember
|
||
|
deriving Inhabited
|
||
|
|
||
|
structure AnalyzerResult where
|
||
|
name2ModIdx : HashMap Name ModuleIdx
|
||
|
moduleNames : Array Name
|
||
|
moduleInfo : HashMap Name Module
|
||
|
hierarchy : Hierarchy
|
||
|
-- Indexed by ModIdx
|
||
|
importAdj : Array (Array Bool)
|
||
|
deriving Inhabited
|
||
|
|
||
|
namespace ModuleMember
|
||
|
|
||
|
def getDeclarationRange : ModuleMember → DeclarationRange
|
||
|
| docInfo i => i.getDeclarationRange
|
||
|
| modDoc i => i.declarationRange
|
||
|
|
||
|
def order (l r : ModuleMember) : Bool :=
|
||
|
Position.lt l.getDeclarationRange.pos r.getDeclarationRange.pos
|
||
|
|
||
|
def getName : ModuleMember → Name
|
||
|
| docInfo i => i.getName
|
||
|
| modDoc i => Name.anonymous
|
||
|
|
||
|
def getDocString : ModuleMember → Option String
|
||
|
| docInfo i => i.getDocString
|
||
|
| modDoc i => i.doc
|
||
|
|
||
|
end ModuleMember
|
||
|
|
||
|
def process : MetaM AnalyzerResult := do
|
||
|
let env ← getEnv
|
||
|
let mut res := mkHashMap env.header.moduleNames.size
|
||
|
for module in env.header.moduleNames do
|
||
|
let modDocs := match getModuleDoc? env module with
|
||
|
| none => #[]
|
||
|
| some ds => ds
|
||
|
|>.map (λ doc => ModuleMember.modDoc doc)
|
||
|
res := res.insert module (Module.mk module modDocs)
|
||
|
|
||
|
for cinfo in env.constants.toList do
|
||
|
try
|
||
|
let analysis := Prod.fst <$> Meta.MetaM.toIO (DocInfo.ofConstant cinfo) { maxHeartbeats := 5000000, options := ⟨[(`pp.tagAppFns, true)]⟩ } { env := env} {} {}
|
||
|
if let some dinfo ← analysis then
|
||
|
let some modidx := env.getModuleIdxFor? dinfo.getName | unreachable!
|
||
|
let moduleName := env.allImportedModuleNames.get! modidx
|
||
|
let module := res.find! moduleName
|
||
|
res := res.insert moduleName {module with members := module.members.push (ModuleMember.docInfo dinfo)}
|
||
|
catch e =>
|
||
|
IO.println s!"WARNING: Failed to obtain information for: {cinfo.fst}: {←e.toMessageData.toString}"
|
||
|
|
||
|
-- TODO: This is definitely not the most efficient way to store this data
|
||
|
let mut adj := Array.mkArray res.size (Array.mkArray res.size false)
|
||
|
-- TODO: This could probably be faster if we did an insertion sort above instead
|
||
|
for (moduleName, module) in res.toArray do
|
||
|
res := res.insert moduleName {module with members := module.members.qsort ModuleMember.order}
|
||
|
let some modIdx := env.getModuleIdx? moduleName | unreachable!
|
||
|
let moduleData := env.header.moduleData.get! modIdx
|
||
|
for imp in moduleData.imports do
|
||
|
let some importIdx := env.getModuleIdx? imp.module | unreachable!
|
||
|
adj := adj.set! modIdx (adj.get! modIdx |>.set! importIdx true)
|
||
|
|
||
|
pure {
|
||
|
name2ModIdx := env.const2ModIdx,
|
||
|
moduleNames := env.header.moduleNames,
|
||
|
moduleInfo := res,
|
||
|
hierarchy := Hierarchy.fromArray env.header.moduleNames,
|
||
|
importAdj := adj
|
||
|
}
|
||
|
|
||
|
def filterMapDocInfo (ms : Array ModuleMember) : Array DocInfo :=
|
||
|
ms.filterMap filter
|
||
|
where
|
||
|
filter : ModuleMember → Option DocInfo
|
||
|
| ModuleMember.docInfo i => some i
|
||
|
| _ => none
|
||
|
|
||
|
end DocGen4.Process
|