diff options
Diffstat (limited to 'doc-tool/src/dotty/tools/dottydoc/core/transform.scala')
-rw-r--r-- | doc-tool/src/dotty/tools/dottydoc/core/transform.scala | 232 |
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) + } +} |