diff options
author | Felix Mulder <felix.mulder@gmail.com> | 2016-07-20 18:33:09 +0200 |
---|---|---|
committer | Felix Mulder <felix.mulder@gmail.com> | 2016-08-19 15:37:32 +0200 |
commit | 553f9b20a10a16ff0348733c0af936cb36148fd5 (patch) | |
tree | ceca2fc7f986f6b1056695a740cc0d5b98c50fd1 /dottydoc/jvm | |
parent | 87ecca23c65564a6e182e52dbfe1d2f2c262b596 (diff) | |
download | dotty-553f9b20a10a16ff0348733c0af936cb36148fd5.tar.gz dotty-553f9b20a10a16ff0348733c0af936cb36148fd5.tar.bz2 dotty-553f9b20a10a16ff0348733c0af936cb36148fd5.zip |
Remove shared directory - nothing shared anymore
Diffstat (limited to 'dottydoc/jvm')
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") + } +} |