aboutsummaryrefslogtreecommitdiff
path: root/doc-tool/src/dotty/tools/dottydoc/core/transform.scala
diff options
context:
space:
mode:
Diffstat (limited to 'doc-tool/src/dotty/tools/dottydoc/core/transform.scala')
-rw-r--r--doc-tool/src/dotty/tools/dottydoc/core/transform.scala232
1 files changed, 232 insertions, 0 deletions
diff --git a/doc-tool/src/dotty/tools/dottydoc/core/transform.scala b/doc-tool/src/dotty/tools/dottydoc/core/transform.scala
new file mode 100644
index 000000000..e4b9ae6b6
--- /dev/null
+++ b/doc-tool/src/dotty/tools/dottydoc/core/transform.scala
@@ -0,0 +1,232 @@
+package dotty.tools
+package dottydoc
+package core
+
+import dotc.CompilationUnit
+import dotc.core.Contexts.Context
+import dotc.core.Comments.ContextDocstrings
+import dotc.core.Phases.Phase
+import model._
+import model.internal._
+import util.syntax._
+import util.traversing._
+
+object transform {
+ /**
+ * The idea behind DocMiniTransformations is to fuse transformations to the
+ * doc AST, much like `MiniPhaseTransform` in dotty core - but in a much more
+ * simple implementation
+ *
+ * Usage
+ * -----
+ *
+ * Create a `DocMiniPhase` which overrides the relevant method:
+ *
+ * ```
+ * override def transformDef(implicit ctx: Context) = {
+ * case x if shouldTransform(x) => x.copy(newValue = ...)
+ * }
+ * ```
+ *
+ * On each node in the AST, the appropriate method in `DocMiniPhase` will be
+ * called in the order that they are supplied in
+ * `DocMiniphaseTransformations`.
+ *
+ * There won't be a match-error as `transformX` is composed with an
+ * `identity` function.
+ *
+ * The transformations in `DocMiniTransformations` will apply transformations
+ * to all nodes - this means that you do _not_ need to transform children in
+ * `transformPackage`, because `transformX` will be called for the relevant
+ * children. If you want to add children to `Package` you need to do that in
+ * `transformPackage`, these additions will be persisted.
+ *
+ * Deleting nodes in the AST
+ * -------------------------
+ * To delete a node in the AST, simply return `NonEntity` from transforming method
+ */
+ trait DocMiniTransformations extends Phase {
+ def transformations: List[DocMiniPhase]
+
+ override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
+ for {
+ pack <- rootPackages(ctx.docbase.packages)
+ transformed = performPackageTransform(pack)
+ } yield ctx.docbase.packagesMutable(pack.name) = transformed
+ units
+ }
+
+ private def performPackageTransform(pack: Package)(implicit ctx: Context): Package = {
+ def transformEntity[E <: Entity](e: E, f: DocMiniPhase => E => E)(createNew: E => E): Entity = {
+ val transformedEntity = transformations.foldLeft(e) { case (oldE, transf) =>
+ f(transf)(oldE)
+ }
+
+ if (transformedEntity eq NonEntity) NonEntity
+ else createNew(transformedEntity)
+ }
+
+ def traverse(ent: Entity): Entity = ent match {
+ case p: Package => transformEntity(p, _.packageTransformation) { p =>
+ val newPackage = PackageImpl(
+ p.symbol,
+ p.annotations,
+ p.name,
+ p.members.map(traverse).filterNot(_ eq NonEntity),
+ p.path,
+ p.superTypes,
+ p.comment,
+ p.parent
+ )
+
+ // Update reference in context to newPackage
+ ctx.docbase.packagesMutable += (newPackage.path.mkString(".") -> newPackage)
+
+ newPackage
+ }
+ case t: TypeAlias => transformEntity(t, _.typeAliasTransformation) { t =>
+ TypeAliasImpl(
+ t.symbol,
+ t.annotations,
+ t.modifiers,
+ t.name,
+ t.path,
+ t.alias,
+ t.comment,
+ t.parent
+ )
+ }
+ case c: Class => transformEntity(c, _.classTransformation) { cls =>
+ ClassImpl(
+ cls.symbol,
+ cls.annotations,
+ cls.name,
+ cls.members.map(traverse).filterNot(_ eq NonEntity),
+ cls.modifiers,
+ cls.path,
+ cls.typeParams,
+ cls.constructors,
+ cls.superTypes,
+ cls.comment,
+ cls.companionPath,
+ cls.parent
+ )
+ }
+ case cc: CaseClass => transformEntity(cc, _.caseClassTransformation) { cc =>
+ CaseClassImpl(
+ cc.symbol,
+ cc.annotations,
+ cc.name,
+ cc.members.map(traverse).filterNot(_ eq NonEntity),
+ cc.modifiers,
+ cc.path,
+ cc.typeParams,
+ cc.constructors,
+ cc.superTypes,
+ cc.comment,
+ cc.companionPath,
+ cc.parent
+ )
+ }
+ case trt: Trait => transformEntity(trt, _.traitTransformation) { trt =>
+ TraitImpl(
+ trt.symbol,
+ trt.annotations,
+ trt.name,
+ trt.members.map(traverse).filterNot(_ eq NonEntity),
+ trt.modifiers,
+ trt.path,
+ trt.typeParams,
+ trt.traitParams,
+ trt.superTypes,
+ trt.comment,
+ trt.companionPath,
+ trt.parent
+ )
+ }
+ case obj: Object => transformEntity(obj, _.objectTransformation) { obj =>
+ ObjectImpl(
+ obj.symbol,
+ obj.annotations,
+ obj.name,
+ obj.members.map(traverse).filterNot(_ eq NonEntity),
+ obj.modifiers,
+ obj.path,
+ obj.superTypes,
+ obj.comment,
+ obj.companionPath,
+ obj.parent
+ )
+ }
+ case df: Def => transformEntity(df, _.defTransformation) { df =>
+ DefImpl(
+ df.symbol,
+ df.annotations,
+ df.name,
+ df.modifiers,
+ df.path,
+ df.returnValue,
+ df.typeParams,
+ df.paramLists,
+ df.comment,
+ df.implicitlyAddedFrom,
+ df.parent
+ )
+ }
+ case vl: Val => transformEntity(vl, _.valTransformation) { vl =>
+ ValImpl(
+ vl.symbol,
+ vl.annotations,
+ vl.name,
+ vl.modifiers,
+ vl.path,
+ vl.returnValue,
+ vl.kind,
+ vl.comment,
+ vl.implicitlyAddedFrom,
+ vl.parent
+ )
+ }
+ }
+
+ traverse(pack).asInstanceOf[Package]
+ }
+
+ override def run(implicit ctx: Context): Unit = ()
+ }
+
+ object DocMiniTransformations {
+ private var previousPhase = 0
+ def apply(miniPhases: DocMiniPhase*) =
+ new DocMiniTransformations {
+ val transformations = miniPhases.toList
+ val packages = Map.empty[String, Package]
+
+ def phaseName = s"MiniTransformation${ previousPhase += 1 }"
+ }
+ }
+
+ trait DocMiniPhase { phase =>
+ private def identity[E]: PartialFunction[E, E] = {
+ case id: E @unchecked => id
+ }
+
+ def transformPackage(implicit ctx: Context): PartialFunction[Package, Package] = identity
+ def transformTypeAlias(implicit ctx: Context): PartialFunction[TypeAlias, TypeAlias] = identity
+ def transformClass(implicit ctx: Context): PartialFunction[Class, Class] = identity
+ def transformCaseClass(implicit ctx: Context): PartialFunction[CaseClass, CaseClass] = identity
+ def transformTrait(implicit ctx: Context): PartialFunction[Trait, Trait] = identity
+ def transformObject(implicit ctx: Context): PartialFunction[Object, Object] = identity
+ def transformDef(implicit ctx: Context): PartialFunction[Def, Def] = identity
+ def transformVal(implicit ctx: Context): PartialFunction[Val, Val] = identity
+
+ private[transform] def packageTransformation(p: Package)(implicit ctx: Context) = (transformPackage orElse identity)(p)
+ private[transform] def typeAliasTransformation(alias: TypeAlias)(implicit ctx: Context) = (transformTypeAlias orElse identity)(alias)
+ private[transform] def classTransformation(cls: Class)(implicit ctx: Context) = (transformClass orElse identity)(cls)
+ private[transform] def caseClassTransformation(cc: CaseClass)(implicit ctx: Context) = (transformCaseClass orElse identity)(cc)
+ private[transform] def traitTransformation(trt: Trait)(implicit ctx: Context) = (transformTrait orElse identity)(trt)
+ private[transform] def objectTransformation(obj: Object)(implicit ctx: Context) = (transformObject orElse identity)(obj)
+ private[transform] def defTransformation(df: Def)(implicit ctx: Context) = (transformDef orElse identity)(df)
+ private[transform] def valTransformation(vl: Val)(implicit ctx: Context) = (transformVal orElse identity)(vl)
+ }
+}