aboutsummaryrefslogtreecommitdiff
path: root/dottydoc/jvm
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2016-07-20 18:33:09 +0200
committerFelix Mulder <felix.mulder@gmail.com>2016-08-19 15:37:32 +0200
commit553f9b20a10a16ff0348733c0af936cb36148fd5 (patch)
treececa2fc7f986f6b1056695a740cc0d5b98c50fd1 /dottydoc/jvm
parent87ecca23c65564a6e182e52dbfe1d2f2c262b596 (diff)
downloaddotty-553f9b20a10a16ff0348733c0af936cb36148fd5.tar.gz
dotty-553f9b20a10a16ff0348733c0af936cb36148fd5.tar.bz2
dotty-553f9b20a10a16ff0348733c0af936cb36148fd5.zip
Remove shared directory - nothing shared anymore
Diffstat (limited to 'dottydoc/jvm')
-rw-r--r--dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/BodyEntities.scala110
-rw-r--r--dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/Comment.scala6
-rw-r--r--dottydoc/jvm/src/dotty/tools/dottydoc/model/entities.scala105
-rw-r--r--dottydoc/jvm/src/dotty/tools/dottydoc/model/factories.scala177
-rw-r--r--dottydoc/jvm/src/dotty/tools/dottydoc/model/internal.scala83
-rw-r--r--dottydoc/jvm/src/dotty/tools/dottydoc/util/Traversing.scala23
6 files changed, 504 insertions, 0 deletions
diff --git a/dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/BodyEntities.scala b/dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/BodyEntities.scala
new file mode 100644
index 000000000..08da81059
--- /dev/null
+++ b/dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/BodyEntities.scala
@@ -0,0 +1,110 @@
+package dotty.tools.dottydoc
+package model
+package comment
+
+import scala.collection._
+
+/** A body of text. A comment has a single body, which is composed of
+ * at least one block. Inside every body is exactly one summary (see
+ * [[scala.tools.nsc.doc.model.comment.Summary]]). */
+final case class Body(blocks: Seq[Block]) {
+
+ /** The summary text of the comment body. */
+ lazy val summary: Option[Body] = {
+ def summaryInBlock(block: Block): Seq[Inline] = block match {
+ case Title(text, _) => summaryInInline(text)
+ case Paragraph(text) => summaryInInline(text)
+ case UnorderedList(items) => items flatMap summaryInBlock
+ case OrderedList(items, _) => items flatMap summaryInBlock
+ case DefinitionList(items) => items.values.toSeq flatMap summaryInBlock
+ case _ => Nil
+ }
+ def summaryInInline(text: Inline): Seq[Inline] = text match {
+ case Summary(text) => List(text)
+ case Chain(items) => items flatMap summaryInInline
+ case Italic(text) => summaryInInline(text)
+ case Bold(text) => summaryInInline(text)
+ case Underline(text) => summaryInInline(text)
+ case Superscript(text) => summaryInInline(text)
+ case Subscript(text) => summaryInInline(text)
+ case Link(_, title) => summaryInInline(title)
+ case _ => Nil
+ }
+ (blocks flatMap summaryInBlock).toList match {
+ case Nil => None
+ case inline :: Nil => Some(Body(Seq(Paragraph(inline))))
+ case inlines => Some(Body(Seq(Paragraph(Chain(inlines)))))
+ }
+ }
+}
+
+/** A block-level element of text, such as a paragraph or code block. */
+sealed abstract class Block
+
+final case class Title(text: Inline, level: Int) extends Block
+final case class Paragraph(text: Inline) extends Block
+final case class Code(data: String) extends Block
+final case class UnorderedList(items: Seq[Block]) extends Block
+final case class OrderedList(items: Seq[Block], style: String) extends Block
+final case class DefinitionList(items: SortedMap[Inline, Block]) extends Block
+final case class HorizontalRule() extends Block
+
+/** An section of text inside a block, possibly with formatting. */
+sealed abstract class Inline
+
+final case class Chain(items: Seq[Inline]) extends Inline
+final case class Italic(text: Inline) extends Inline
+final case class Bold(text: Inline) extends Inline
+final case class Underline(text: Inline) extends Inline
+final case class Superscript(text: Inline) extends Inline
+final case class Subscript(text: Inline) extends Inline
+final case class Link(target: String, title: Inline) extends Inline
+final case class Monospace(text: Inline) extends Inline
+final case class Text(text: String) extends Inline
+abstract class EntityLink(val title: Inline) extends Inline { def link: LinkTo }
+object EntityLink {
+ def apply(title: Inline, linkTo: LinkTo) = new EntityLink(title) { def link: LinkTo = linkTo }
+ def unapply(el: EntityLink): Option[(Inline, LinkTo)] = Some((el.title, el.link))
+}
+final case class HtmlTag(data: String) extends Inline {
+ private val Pattern = """(?ms)\A<(/?)(.*?)[\s>].*\z""".r
+ private val (isEnd, tagName) = data match {
+ case Pattern(s1, s2) =>
+ (! s1.isEmpty, Some(s2.toLowerCase))
+ case _ =>
+ (false, None)
+ }
+
+ def canClose(open: HtmlTag) = {
+ isEnd && tagName == open.tagName
+ }
+
+ private val TagsNotToClose = Set("br", "img")
+ def close = tagName collect { case name if !TagsNotToClose(name) => HtmlTag(s"</$name>") }
+}
+
+/** The summary of a comment, usually its first sentence. There must be exactly one summary per body. */
+final case class Summary(text: Inline) extends Inline
+
+sealed trait LinkTo
+final case class LinkToExternal(name: String, url: String) extends LinkTo
+final case class Tooltip(name: String) extends LinkTo
+
+/** Linking directly to entities is not picklable because of cyclic references */
+final case class LinkToEntity(entity: Entity) extends LinkTo
+
+/** Use MaterializableLink for entities that need be picklable */
+sealed trait MaterializableLink { def title: String }
+final case class UnsetLink(title: String, query: String) extends MaterializableLink
+final case class MaterializedLink(title: String, target: String) extends MaterializableLink
+final case class NoLink(title: String, target: String) extends MaterializableLink
+
+sealed trait Reference
+final case class TypeReference(title: String, tpeLink: MaterializableLink, paramLinks: List[Reference]) extends Reference
+final case class OrTypeReference(left: Reference, right: Reference) extends Reference
+final case class AndTypeReference(left: Reference, right: Reference) extends Reference
+final case class FunctionReference(args: List[Reference], returnValue: Reference) extends Reference
+final case class TupleReference(args: List[Reference]) extends Reference
+final case class BoundsReference(low: Reference, high: Reference) extends Reference
+final case class NamedReference(title: String, ref: Reference, isByName: Boolean = false, isRepeated: Boolean = false) extends Reference
+final case class ConstantReference(title: String) extends Reference
diff --git a/dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/Comment.scala b/dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/Comment.scala
new file mode 100644
index 000000000..ad53b9ae7
--- /dev/null
+++ b/dottydoc/jvm/src/dotty/tools/dottydoc/model/comment/Comment.scala
@@ -0,0 +1,6 @@
+package dotty.tools
+package dottydoc
+package model
+package comment
+
+case class Comment(body: String, short: String)
diff --git a/dottydoc/jvm/src/dotty/tools/dottydoc/model/entities.scala b/dottydoc/jvm/src/dotty/tools/dottydoc/model/entities.scala
new file mode 100644
index 000000000..391bd514f
--- /dev/null
+++ b/dottydoc/jvm/src/dotty/tools/dottydoc/model/entities.scala
@@ -0,0 +1,105 @@
+package dotty.tools.dottydoc
+package model
+
+import comment.{ Comment, MaterializableLink, Reference, NamedReference }
+
+trait Entity {
+ def name: String
+
+ /** Path from root, i.e. `scala.Option$` */
+ def path: List[String]
+
+ def comment: Option[Comment]
+
+ def kind: String
+
+ def parent: Entity
+
+ /** All parents from package level i.e. Package to Object to Member etc */
+ def parents: List[Entity] = parent match {
+ case NonEntity => Nil
+ case e => e :: e.parents
+ }
+
+ /** Applies `f` to entity if != `NonEntity` */
+ def fold[A](nonEntity: A)(f: Entity => A) = this match {
+ case NonEntity => nonEntity
+ case x => f(x)
+ }
+}
+
+trait SuperTypes {
+ def superTypes: List[MaterializableLink]
+}
+
+trait Members {
+ def members: List[Entity]
+}
+
+trait Modifiers {
+ def modifiers: List[String]
+
+ val isPrivate: Boolean =
+ modifiers.contains("private")
+}
+
+trait TypeParams {
+ def typeParams: List[String]
+}
+
+trait ReturnValue {
+ def returnValue: Reference
+}
+
+trait ParamList {
+ def list: List[NamedReference]
+ def isImplicit: Boolean
+}
+
+trait Package extends Entity with Members {
+ val kind = "package"
+
+ def children: List[Entity with Members]
+}
+
+trait Class extends Entity with Modifiers with TypeParams with SuperTypes with Members {
+ val kind = "class"
+}
+
+trait CaseClass extends Entity with Modifiers with TypeParams with SuperTypes with Members {
+ override val kind = "case class"
+}
+
+trait Trait extends Entity with Modifiers with TypeParams with SuperTypes with Members {
+ override val kind = "trait"
+}
+
+trait Object extends Entity with Modifiers with SuperTypes with Members {
+ override val kind = "object"
+}
+
+trait Def extends Entity with Modifiers with TypeParams with ReturnValue {
+ def paramLists: List[ParamList]
+ val kind = "def"
+}
+
+trait Val extends Entity with Modifiers with ReturnValue {
+ val kind = "val"
+}
+
+trait Var extends Entity with Modifiers with ReturnValue {
+ val kind = "var"
+}
+
+trait NonEntity extends Entity {
+ val name = ""
+ val comment = None
+ val path = Nil
+ val kind = ""
+ val parent = NonEntity
+}
+
+final case object NonEntity extends NonEntity
+final case object RootEntity extends NonEntity {
+ override val name = "root"
+}
diff --git a/dottydoc/jvm/src/dotty/tools/dottydoc/model/factories.scala b/dottydoc/jvm/src/dotty/tools/dottydoc/model/factories.scala
new file mode 100644
index 000000000..f0c78fa41
--- /dev/null
+++ b/dottydoc/jvm/src/dotty/tools/dottydoc/model/factories.scala
@@ -0,0 +1,177 @@
+package dotty.tools.dottydoc
+package model
+
+import comment._
+import dotty.tools.dotc
+import dotc.core.Types._
+import dotc.core.TypeApplications._
+import dotc.core.Flags
+import dotc.core.Contexts.Context
+import dotc.core.Symbols.Symbol
+import dotty.tools.dotc.core.SymDenotations._
+import dotty.tools.dotc.core.Names.TypeName
+import dotc.core.{ Flags => DottyFlags }
+import dotc.ast.Trees._
+
+
+object factories {
+ import dotty.tools.dotc.ast.tpd._
+ import dotty.tools.dottydoc.model.internal.ParamListImpl
+ import DottyFlags._
+
+ type TypeTree = dotty.tools.dotc.ast.Trees.Tree[Type]
+
+ def flags(t: Tree)(implicit ctx: Context): List[String] =
+ (t.symbol.flags & SourceModifierFlags)
+ .flagStrings.toList
+ .filter(_ != "<trait>")
+ .filter(_ != "interface")
+
+ def path(sym: Symbol)(implicit ctx: Context): List[String] = sym match {
+ case sym if sym.name.decode.toString == "<root>" => Nil
+ case sym if sym is Flags.Module => path(sym.owner) :+ sym.name.decode.toString.dropRight(1)
+ case sym => path(sym.owner) :+ sym.name.decode.toString
+ }
+
+
+ private val product = """Product[1-9][0-9]*""".r
+ private def cleanTitle(title: String): String = title match {
+ // matches Entity.this.Something
+ case x if x matches "[^\\[]+\\.this\\..+" => x.split("\\.").last
+ // Matches Entity[P, ...]
+ case x if x matches "[^\\[]+\\[[^\\]]+\\]" =>
+ val Array(tpe, params) = x.dropRight(1).split("\\[")
+ s"""$tpe[${params.split(",").map(x => cleanTitle(x.trim)).mkString(", ")}]"""
+ case _ => title
+ }
+
+ private def cleanQuery(query: String): String = query match {
+ case x if x matches "[^\\[]+\\[[^\\]]+\\]" => x.takeWhile(_ != '[')
+ case _ => query
+ }
+
+ def returnType(t: Type)(implicit ctx: Context): Reference = {
+ val defn = ctx.definitions
+
+ def typeRef(name: String, query: String = "", params: List[Reference] = Nil) = {
+ val realQuery = if (query != "") query else name
+ TypeReference(name, UnsetLink(name, realQuery), params)
+ }
+
+ def expandTpe(t: Type, params: List[Reference] = Nil): Reference = t match {
+ case tl: TypeLambda =>
+ //FIXME: should be handled correctly
+ // example, in `Option`:
+ //
+ // {{{
+ // def companion: GenericCompanion[collection.Iterable]
+ // }}}
+ //
+ // Becomes: def companion: [+X0] -> collection.Iterable[X0]
+ typeRef(tl.show + " (not handled)")
+ case AppliedType(tycon, args) =>
+ val cls = tycon.typeSymbol
+ if (tycon.isRepeatedParam)
+ expandTpe(args.head)
+ else if (defn.isFunctionClass(cls))
+ FunctionReference(args.init.map(expandTpe(_, Nil)), expandTpe(args.last))
+ else if (defn.isTupleClass(cls))
+ TupleReference(args.map(expandTpe(_, Nil)))
+ else {
+ val query = tycon.show
+ val name = query.split("\\.").last
+ typeRef(name, query, params = args.map(expandTpe(_, Nil)))
+ }
+
+ case ref @ RefinedType(parent, rn, info) =>
+ expandTpe(parent) //FIXME: will be a refined HK, aka class Foo[X] { def bar: List[X] } or similar
+ case ref @ HKApply(tycon, args) =>
+ expandTpe(tycon, args.map(expandTpe(_, params)))
+ case TypeRef(_, n) =>
+ val name = n.decode.toString.split("\\$").last
+ typeRef(name, params = params)
+ case ta: TypeAlias =>
+ expandTpe(ta.alias.widenDealias)
+ case OrType(left, right) =>
+ OrTypeReference(expandTpe(left), expandTpe(right))
+ case AndType(left, right) =>
+ AndTypeReference(expandTpe(left), expandTpe(right))
+ case tb @ TypeBounds(lo, hi) =>
+ BoundsReference(expandTpe(lo), expandTpe(hi))
+ case AnnotatedType(tpe, _) =>
+ expandTpe(tpe)
+ case ExprType(tpe) =>
+ expandTpe(tpe)
+ case c: ConstantType =>
+ ConstantReference(c.show)
+ case tt: ThisType =>
+ expandTpe(tt.underlying)
+ case ci: ClassInfo =>
+ typeRef(ci.cls.show)
+ case mt: MethodType =>
+ expandTpe(mt.resultType)
+ case pt: PolyType =>
+ expandTpe(pt.resultType)
+ case pp: PolyParam =>
+ val paramName = pp.paramName.show
+ val name =
+ if (paramName.contains('$'))
+ paramName.split("\\$\\$").last
+ else paramName
+
+ typeRef(name)
+ }
+
+ expandTpe(t)
+ }
+
+ def typeParams(sym: Symbol)(implicit ctx: Context): List[String] =
+ sym.denot.info match {
+ case pt: PolyType =>
+ pt.paramNames.map(_.show.split("\\$").last)
+ case _ => Nil
+ }
+
+ def paramLists(tpe: Type)(implicit ctx: Context): List[ParamList] = tpe match {
+ case pt: PolyType =>
+ paramLists(pt.resultType)
+
+ case mt: MethodType =>
+ ParamListImpl(mt.paramNames.zip(mt.paramTypes).map { case (name, tpe) =>
+ NamedReference(
+ name.decode.toString,
+ returnType(tpe),
+ isByName = tpe.isInstanceOf[ExprType],
+ isRepeated = tpe.isRepeatedParam
+ )
+ }, mt.isImplicit) :: paramLists(mt.resultType)
+
+ case annot: AnnotatedType => paramLists(annot.tpe)
+ case (_: PolyParam | _: RefinedType | _: TypeRef | _: ThisType |
+ _: ExprType | _: OrType | _: AndType | _: HKApply) => Nil // return types should not be in the paramlist
+ }
+
+ def superTypes(t: Tree)(implicit ctx: Context): List[MaterializableLink] = t.symbol.denot match {
+ case cd: ClassDenotation =>
+ def isJavaLangObject(prefix: Type): Boolean =
+ prefix match {
+ case TypeRef(ThisType(TypeRef(NoPrefix, outerName)), innerName) =>
+ outerName.toString == "lang" && innerName.toString == "Object"
+ case _ => false
+ }
+
+ def isProductWithArity(prefix: Type): Boolean = prefix match {
+ case TypeRef(TermRef(TermRef(NoPrefix, root), scala), prod) =>
+ root.toString == "_root_" &&
+ scala.toString == "scala" &&
+ product.findFirstIn(prod.toString).isDefined
+ case _ => false
+ }
+
+ cd.classParents.collect {
+ case t: TypeRef if !isJavaLangObject(t) && !isProductWithArity(t) =>
+ UnsetLink(t.name.toString, path(t.symbol).mkString("."))
+ }
+ case _ => Nil
+ }
+}
diff --git a/dottydoc/jvm/src/dotty/tools/dottydoc/model/internal.scala b/dottydoc/jvm/src/dotty/tools/dottydoc/model/internal.scala
new file mode 100644
index 000000000..ec1adfa88
--- /dev/null
+++ b/dottydoc/jvm/src/dotty/tools/dottydoc/model/internal.scala
@@ -0,0 +1,83 @@
+package dotty.tools.dottydoc
+package model
+
+import comment.{ Comment, MaterializableLink, Reference, NamedReference }
+
+object internal {
+
+ trait Impl {
+ var parent: Entity = NonEntity
+ }
+
+ final case class PackageImpl(
+ name: String,
+ var members: List[Entity],
+ path: List[String],
+ var comment: Option[Comment] = None
+ ) extends Package with Impl {
+ def children: List[Entity with Members] =
+ members.collect { case x: Entity with Members => x }
+ }
+
+ final case class ClassImpl(
+ name: String,
+ members: List[Entity],
+ modifiers: List[String],
+ path: List[String],
+ var typeParams: List[String] = Nil,
+ var superTypes: List[MaterializableLink] = Nil,
+ var comment: Option[Comment] = None
+ ) extends Class with Impl
+
+ final case class CaseClassImpl(
+ name: String,
+ members: List[Entity],
+ modifiers: List[String],
+ path: List[String],
+ var typeParams: List[String] = Nil,
+ var superTypes: List[MaterializableLink] = Nil,
+ var comment: Option[Comment] = None
+ ) extends CaseClass with Impl
+
+ final case class TraitImpl(
+ name: String,
+ members: List[Entity],
+ modifiers: List[String],
+ path: List[String],
+ var typeParams: List[String] = Nil,
+ var superTypes: List[MaterializableLink] = Nil,
+ var comment: Option[Comment] = None
+ ) extends Trait with Impl
+
+ final case class ObjectImpl(
+ name: String,
+ members: List[Entity],
+ modifiers: List[String],
+ path: List[String],
+ var superTypes: List[MaterializableLink] = Nil,
+ var comment: Option[Comment] = None
+ ) extends Object with Impl
+
+ final case class DefImpl(
+ name: String,
+ modifiers: List[String],
+ path: List[String],
+ var returnValue: Reference,
+ var typeParams: List[String] = Nil,
+ var paramLists: List[ParamList] = Nil,
+ var comment: Option[Comment] = None
+ ) extends Def with Impl
+
+ final case class ValImpl(
+ name: String,
+ modifiers: List[String],
+ path: List[String],
+ var returnValue: Reference,
+ var comment: Option[Comment] = None
+ ) extends Val with Impl
+
+ final case class ParamListImpl(
+ list: List[NamedReference],
+ isImplicit: Boolean
+ ) extends ParamList
+}
diff --git a/dottydoc/jvm/src/dotty/tools/dottydoc/util/Traversing.scala b/dottydoc/jvm/src/dotty/tools/dottydoc/util/Traversing.scala
new file mode 100644
index 000000000..2ac8eae4f
--- /dev/null
+++ b/dottydoc/jvm/src/dotty/tools/dottydoc/util/Traversing.scala
@@ -0,0 +1,23 @@
+package dotty.tools.dottydoc
+package util
+
+object traversing {
+ import model._
+
+ def mutateEntities(e: Entity)(trans: Entity => Unit): Unit = e match {
+ case e: Entity with Members =>
+ trans(e)
+ e.members.map(mutateEntities(_)(trans))
+ case e: Entity => trans(e)
+ }
+
+ def relativePath(from: Entity, to: Entity) = {
+ val offset = from match {
+ case _: Val | _: Def => 2
+ case _ => 1
+ }
+
+ "../" * (from.path.length - offset) +
+ to.path.mkString("", "/", ".html")
+ }
+}