aboutsummaryrefslogtreecommitdiff
path: root/dottydoc/jvm/src/dotty/tools/dottydoc/core/Phases.scala
blob: a525723639c4afb78472821118b106d429c865c9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package dotty.tools
package dottydoc
package core

/** Dotty and Dottydoc imports */
import dotc.ast.Trees._
import dotc.CompilationUnit
import dotc.config.Printers.dottydoc
import dotc.core.Contexts.Context
import dotc.core.Phases.Phase
import dotc.core.Symbols.Symbol

object Phases {

  class DocPhase extends Phase {
    import model.comment.Comment
    import model.CommentParsers.wikiParser
    import model.Entities._
    import model.EntityFactories._
    import dotty.tools.dotc.core.Flags
    import dotty.tools.dotc.ast.tpd._

    def phaseName = "docphase"

    /** Build documentation hierarchy from existing tree */
    def collect(tree: Tree)(implicit ctx: Context): Entity = {

      def collectList(xs: List[Tree])(implicit ctx: Context): List[Entity] =
        xs.map(collect).filter(_ != NonEntity)

      def collectPackageMembers(xs: List[Tree])(implicit ctx: Context): List[PackageMember] =
        collectList(xs).asInstanceOf[List[PackageMember]]

      def collectMembers(tree: Tree)(implicit ctx: Context): List[Entity] = tree match {
        case t: Template => collectList(t.body)
        case _ => Nil
      }

      val comment =
        ctx.base.docstring(tree.symbol).map(c => Comment(wikiParser.parseHtml(c)))

      tree match {
        /** package */
        case p @ PackageDef(pid, st) =>
          val name = pid.name.toString
          Package(name, collectPackageMembers(st), comment, path(p, name))

        /** trait */
        case t @ TypeDef(n, rhs) if t.symbol.is(Flags.Trait) =>
          val name = n.toString
          Trait(name, collectMembers(rhs), comment, flags(t), path(t, name))

        /** objects, on the format "Object$" so drop the last letter */
        case o @ TypeDef(n, rhs) if o.symbol.is(Flags.Module) =>
          val name = n.toString.dropRight(1)
          Object(name, collectMembers(rhs), comment, flags(o), path(o, name))

        /** class / case class */
        case c @ TypeDef(name, rhs) if c.symbol.isClass =>
          (name.toString, collectMembers(rhs), comment, flags(c), path(c, name.toString)) match {
            case x if c.symbol.is(Flags.CaseClass) => CaseClass.tupled(x)
            case x => Class.tupled(x)
          }

        /** def */
        case d: DefDef =>
          Def(d.name.toString, comment, flags(d), path(d, d.name.toString))

        /** val */
        case v: ValDef if !v.symbol.is(Flags.ModuleVal) =>
          Val(v.name.toString, comment, flags(v), path(v, v.name.toString))

        case x => {
          dottydoc.println(s"Found unwanted entity: $x (${x.pos}, ${comment})\n${x.show}")
          NonEntity
        }
      }
    }

    var packages: Map[String, Package] = Map.empty

    def addEntity(p: Package): Unit = {
      val path = p.path.mkString(".")
      packages = packages + (path -> packages.get(path).map { ex =>
        val children = (ex.children ::: p.children).distinct.sortBy(_.name)
        val comment = ex.comment.orElse(p.comment)
        Package(p.name, children, comment, p.path)
      }.getOrElse(p))
    }

    override def run(implicit ctx: Context): Unit =
      collect(ctx.compilationUnit.tpdTree) match {
        case p: Package => addEntity(p)
        case _ => ()
      }

    override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
      val compUnits = super.runOn(units)
      util.IndexWriters.writeJs(packages, "../js/out")
      compUnits
    }
  }

}