diff options
author | Felix Mulder <felix.mulder@gmail.com> | 2016-09-21 15:02:30 +0200 |
---|---|---|
committer | Felix Mulder <felix.mulder@gmail.com> | 2016-10-06 17:45:39 +0200 |
commit | 92536168e9fda4005a8eff54e5ca72cc70fb32e4 (patch) | |
tree | 285d92137cc5c33a0dba3b352b6fa252ed57ce13 /src | |
parent | 208232aba52903ae090711589e9c572dc5347651 (diff) | |
download | dotty-92536168e9fda4005a8eff54e5ca72cc70fb32e4.tar.gz dotty-92536168e9fda4005a8eff54e5ca72cc70fb32e4.tar.bz2 dotty-92536168e9fda4005a8eff54e5ca72cc70fb32e4.zip |
Separate `ContextDocstrings` from `Context` and make it pluggable
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/core/Comments.scala | 47 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Contexts.scala | 34 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Docstrings.scala | 56 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 45 | ||||
-rw-r--r-- | src/dotty/tools/dotc/util/CommentParsing.scala | 7 |
7 files changed, 104 insertions, 91 deletions
diff --git a/src/dotty/tools/dotc/core/Comments.scala b/src/dotty/tools/dotc/core/Comments.scala index 4f36b3b6b..8c2443c9d 100644 --- a/src/dotty/tools/dotc/core/Comments.scala +++ b/src/dotty/tools/dotc/core/Comments.scala @@ -2,17 +2,40 @@ package dotty.tools package dotc package core -import dotc.ast.{ untpd, tpd } -import Decorators._ -import Symbols._ -import Contexts.Context -import Flags.EmptyFlags -import dotc.util.SourceFile -import dotc.util.Positions._ -import dotc.util.CommentParsing._ -import dotc.parsing.Parsers.Parser +import ast.{ untpd, tpd } +import Decorators._, Symbols._, Contexts._, Flags.EmptyFlags +import util.SourceFile +import util.Positions._ +import util.CommentParsing._ +import util.Property.Key +import parsing.Parsers.Parser object Comments { + val ContextDoc = new Key[ContextDocstrings] + + /** Decorator for getting docbase out of context */ + implicit class CommentsContext(val ctx: Context) extends AnyVal { + def docCtx: Option[ContextDocstrings] = ctx.property(ContextDoc) + } + + /** Context for Docstrings, contains basic functionality for getting + * docstrings via `Symbol` and expanding templates + */ + class ContextDocstrings { + import scala.collection.mutable + + private[this] val _docstrings: mutable.Map[Symbol, Comment] = + mutable.Map.empty + + val templateExpander = new CommentExpander + + def docstrings: Map[Symbol, Comment] = _docstrings.toMap + + def docstring(sym: Symbol): Option[Comment] = _docstrings.get(sym) + + def addDocstring(sym: Symbol, doc: Option[Comment]): Unit = + doc.map(d => _docstrings += (sym -> d)) + } abstract case class Comment(pos: Position, raw: String)(implicit ctx: Context) { self => def isExpanded: Boolean @@ -155,7 +178,7 @@ object Comments { */ def cookedDocComment(sym: Symbol, docStr: String = "")(implicit ctx: Context): String = cookedDocComments.getOrElseUpdate(sym, { var ownComment = - if (docStr.length == 0) ctx.getDocbase.flatMap(_.docstring(sym).map(c => template(c.raw))).getOrElse("") + if (docStr.length == 0) ctx.docCtx.flatMap(_.docstring(sym).map(c => template(c.raw))).getOrElse("") else template(docStr) ownComment = replaceInheritDocToInheritdoc(ownComment) @@ -365,7 +388,7 @@ object Comments { def defineVariables(sym: Symbol)(implicit ctx: Context) = { val Trim = "(?s)^[\\s&&[^\n\r]]*(.*?)\\s*$".r - val raw = ctx.getDocbase.flatMap(_.docstring(sym).map(_.raw)).getOrElse("") + val raw = ctx.docCtx.flatMap(_.docstring(sym).map(_.raw)).getOrElse("") defs(sym) ++= defines(raw).map { str => { val start = skipWhitespace(str, "@define".length) @@ -406,7 +429,7 @@ object Comments { * the position of the doc comment of the overridden version is returned instead. */ def docCommentPos(sym: Symbol)(implicit ctx: Context): Position = - ctx.getDocbase.flatMap(_.docstring(sym).map(_.pos)).getOrElse(NoPosition) + ctx.docCtx.flatMap(_.docstring(sym).map(_.pos)).getOrElse(NoPosition) /** A version which doesn't consider self types, as a temporary measure: * an infinite loop has broken out between superComment and cookedDocComment diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index bf171bf60..5c9fdaf88 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -69,9 +69,6 @@ object Contexts { /** The context base at the root */ val base: ContextBase - /** Documentation base */ - def getDocbase = property(DocContext) - /** All outer contexts, ending in `base.initialCtx` and then `NoContext` */ def outersIterator = new Iterator[Context] { var current = thiscontext @@ -578,37 +575,6 @@ object Contexts { } } - val DocContext = new Key[DocBase] - class DocBase { - private[this] val _docstrings: mutable.Map[Symbol, Comment] = - mutable.Map.empty - - val templateExpander = new CommentExpander - - def docstrings: Map[Symbol, Comment] = _docstrings.toMap - - def docstring(sym: Symbol): Option[Comment] = _docstrings.get(sym) - - def addDocstring(sym: Symbol, doc: Option[Comment]): Unit = - doc.map(d => _docstrings += (sym -> d)) - - /* - * Dottydoc places instances of `Package` in this map - but we do not want - * to depend on `dottydoc` for the compiler, as such this is defined as a - * map of `String -> AnyRef` - */ - private[this] val _packages: mutable.Map[String, AnyRef] = mutable.Map.empty - def packagesAs[A]: mutable.Map[String, A] = _packages.asInstanceOf[mutable.Map[String, A]] - - /** Should perhaps factorize this into caches that get flushed */ - private var _defs: Map[Symbol, Set[Symbol]] = Map.empty - def defs(sym: Symbol): Set[Symbol] = _defs.get(sym).getOrElse(Set.empty) - - def addDef(s: Symbol, d: Symbol): Unit = _defs = (_defs + { - s -> _defs.get(s).map(xs => xs + d).getOrElse(Set(d)) - }) - } - /** The essential mutable state of a context base, collected into a common class */ class ContextState { // Symbols state diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index e2cb378b5..5a5eacd18 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -3,7 +3,7 @@ package dotc package core import Periods._, Contexts._, Symbols._, Denotations._, Names._, NameOps._, Annotations._ -import Types._, Flags._, Decorators._, DenotTransformers._, StdNames._, Scopes._ +import Types._, Flags._, Decorators._, DenotTransformers._, StdNames._, Scopes._, Comments._ import NameOps._ import Scopes.Scope import collection.mutable @@ -1541,7 +1541,7 @@ object SymDenotations { /** Enter a symbol in given `scope` without potentially replacing the old copy. */ def enterNoReplace(sym: Symbol, scope: MutableScope)(implicit ctx: Context): Unit = { - def isUsecase = ctx.property(DocContext).isDefined && sym.name.show.takeRight(4) == "$doc" + def isUsecase = ctx.docCtx.isDefined && sym.name.show.takeRight(4) == "$doc" require( (sym.denot.flagsUNSAFE is Private) || !(this is Frozen) || diff --git a/src/dotty/tools/dotc/typer/Docstrings.scala b/src/dotty/tools/dotc/typer/Docstrings.scala new file mode 100644 index 000000000..370844e65 --- /dev/null +++ b/src/dotty/tools/dotc/typer/Docstrings.scala @@ -0,0 +1,56 @@ +package dotty.tools +package dotc +package typer + +import core._ +import Contexts._, Symbols._, Decorators._, Comments._ +import util.Positions._ +import ast.tpd + +trait Docstrings { self: Typer => + + /** The Docstrings typer will handle the expansion of `@define` and + * `@inheritdoc` if there is a `DocContext` present as a property in the + * supplied `ctx`. + * + * It will also type any `@usecase` available in function definitions. + */ + def cookComments(syms: List[Symbol], owner: Symbol)(implicit ctx: Context): Unit = + ctx.docCtx.foreach { docbase => + val relevantSyms = syms.filter(docbase.docstring(_).isDefined) + relevantSyms.foreach { sym => + expandParentDocs(sym) + val usecases = docbase.docstring(sym).map(_.usecases).getOrElse(Nil) + + usecases.foreach { usecase => + enterSymbol(createSymbol(usecase.untpdCode)) + + typedStats(usecase.untpdCode :: Nil, owner) match { + case List(df: tpd.DefDef) => usecase.tpdCode = df + case _ => ctx.error("`@usecase` was not a valid definition", usecase.codePos) + } + } + } + } + + private def expandParentDocs(sym: Symbol)(implicit ctx: Context): Unit = + ctx.docCtx.foreach { docCtx => + docCtx.docstring(sym).foreach { cmt => + def expandDoc(owner: Symbol): Unit = if (!cmt.isExpanded) { + val tplExp = docCtx.templateExpander + tplExp.defineVariables(sym) + + val newCmt = cmt + .expand(tplExp.expandedDocComment(sym, owner, _)) + .withUsecases + + docCtx.addDocstring(sym, Some(newCmt)) + } + + if (sym ne NoSymbol) { + expandParentDocs(sym.owner) + expandDoc(sym.owner) + } + } + } +} diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 938b280d1..4f4278468 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -457,7 +457,7 @@ class Namer { typer: Typer => def setDocstring(sym: Symbol, tree: Tree)(implicit ctx: Context) = tree match { case t: MemberDef if t.rawComment.isDefined => - ctx.getDocbase.foreach(_.addDocstring(sym, t.rawComment)) + ctx.docCtx.foreach(_.addDocstring(sym, t.rawComment)) case _ => () } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 3ed6c9228..3e3bb32f5 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -58,7 +58,7 @@ object Typer { assert(tree.pos.exists, s"position not set for $tree # ${tree.uniqueId}") } -class Typer extends Namer with TypeAssigner with Applications with Implicits with Dynamic with Checking { +class Typer extends Namer with TypeAssigner with Applications with Implicits with Dynamic with Checking with Docstrings { import Typer._ import tpd.{cpy => _, _} @@ -1247,8 +1247,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val dummy = localDummy(cls, impl) val body1 = typedStats(impl.body, dummy)(inClassContext(self1.symbol)) - if (ctx.property(DocContext).isDefined) - typedUsecases(body1.map(_.symbol), self1.symbol)(localContext(cdef, cls).setNewScope) + // Expand comments and type usecases + cookComments(body1.map(_.symbol), self1.symbol)(localContext(cdef, cls).setNewScope) checkNoDoubleDefs(cls) val impl1 = cpy.Template(impl)(constr1, parents1, self1, body1) @@ -1538,45 +1538,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit tpd.cpy.DefDef(mdef)(rhs = Inliner.bodyToInline(mdef.symbol)) :: Inliner.removeInlineAccessors(mdef.symbol) - private def typedUsecases(syms: List[Symbol], owner: Symbol)(implicit ctx: Context): Unit = - ctx.getDocbase.foreach { docbase => - val relevantSyms = syms.filter(docbase.docstring(_).isDefined) - relevantSyms.foreach { sym => - expandParentDocs(sym) - val usecases = docbase.docstring(sym).map(_.usecases).getOrElse(Nil) - - usecases.foreach { usecase => - enterSymbol(createSymbol(usecase.untpdCode)) - - typedStats(usecase.untpdCode :: Nil, owner) match { - case List(df: tpd.DefDef) => usecase.tpdCode = df - case _ => ctx.error("`@usecase` was not a valid definition", usecase.codePos) - } - } - } - } - - private def expandParentDocs(sym: Symbol)(implicit ctx: Context): Unit = - ctx.getDocbase.foreach { docbase => - docbase.docstring(sym).foreach { cmt => - def expandDoc(owner: Symbol): Unit = if (!cmt.isExpanded) { - val tplExp = docbase.templateExpander - tplExp.defineVariables(sym) - - val newCmt = cmt - .expand(tplExp.expandedDocComment(sym, owner, _)) - .withUsecases - - docbase.addDocstring(sym, Some(newCmt)) - } - - if (sym ne NoSymbol) { - expandParentDocs(sym.owner) - expandDoc(sym.owner) - } - } - } - def typedExpr(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = typed(tree, pt)(ctx retractMode Mode.PatternOrType) def typedType(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = // todo: retract mode between Type and Pattern? diff --git a/src/dotty/tools/dotc/util/CommentParsing.scala b/src/dotty/tools/dotc/util/CommentParsing.scala index 077776b5d..cc790d683 100644 --- a/src/dotty/tools/dotc/util/CommentParsing.scala +++ b/src/dotty/tools/dotc/util/CommentParsing.scala @@ -5,6 +5,13 @@ */ package dotty.tools.dotc.util +/** The comment parsing in `dotc` is used by both the comment cooking and the + * dottydoc tool. + * + * The comment cooking is used to expand comments with `@inheritdoc` and + * `@define` annotations. The rest of the comment is untouched and later + * handled by dottydoc. + */ object CommentParsing { import scala.reflect.internal.Chars._ |