diff options
Diffstat (limited to 'dottydoc/jvm/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala')
-rw-r--r-- | dottydoc/jvm/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/dottydoc/jvm/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala b/dottydoc/jvm/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala new file mode 100644 index 000000000..ba7ea040a --- /dev/null +++ b/dottydoc/jvm/src/dotty/tools/dottydoc/core/MiniPhaseTransform.scala @@ -0,0 +1,189 @@ +package dotty.tools +package dottydoc +package core + +import dotc.CompilationUnit +import dotc.core.Contexts.Context +import dotc.core.Phases.Phase +import model._ +import model.internal._ + +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. + */ + abstract class DocMiniTransformations(transformations: List[DocMiniPhase]) extends Phase { + + override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = { + for { + rootName <- rootPackages + pack = ctx.base.packages[Package](rootName) + transformed = performPackageTransform(pack) + } yield ctx.base.packages(rootName) = transformed + super.runOn(units) + } + + private def rootPackages(implicit ctx: Context): List[String] = { + var currentDepth = Int.MaxValue + var packs = List.empty[String] + + for (key <- ctx.base.packages.keys) { + val keyDepth = key.split("\\.").length + packs = + if (keyDepth < currentDepth) { + currentDepth = keyDepth + key :: Nil + } else if (keyDepth == currentDepth) { + key :: packs + } else packs + } + packs + } + + private def performPackageTransform(pack: Package)(implicit ctx: Context): Package = { + def transformEntity[E <: Entity](e: E, f: DocMiniPhase => E => E)(createNew: E => E): E = { + val transformedEntity = transformations.foldLeft(e) { case (oldE, transf) => + f(transf)(oldE) + } + createNew(transformedEntity) + } + + def traverse(ent: Entity): Entity = ent match { + case p: Package => transformEntity(p, _.packageTransformation) { p => + PackageImpl( + p.name, + p.members.map(traverse), + p.path, + p.comment + ) + } + case c: Class => transformEntity(c, _.classTransformation) { newClass => + ClassImpl( + newClass.name, + newClass.members.map(traverse), + newClass.modifiers, + newClass.path, + newClass.typeParams, + newClass.superTypes, + newClass.comment + ) + } + case cc: CaseClass => transformEntity(cc, _.cclassTransformation) { cc => + CaseClassImpl( + cc.name, + cc.members.map(traverse), + cc.modifiers, + cc.path, + cc.typeParams, + cc.superTypes, + cc.comment + ) + } + case trt: Trait => transformEntity(trt, _.traitTransformation) { trt => + TraitImpl( + trt.name, + trt.members.map(traverse), + trt.modifiers, + trt.path, + trt.typeParams, + trt.superTypes, + trt.comment + ) + } + case obj: Object => transformEntity(obj, _.objectTransformation) { obj => + ObjectImpl( + obj.name, + obj.members.map(traverse), + obj.modifiers, + obj.path, + obj.superTypes, + obj.comment + ) + } + case df: Def => transformEntity(df, _.defTransformation) { df => + DefImpl( + df.name, + df.modifiers, + df.path, + df.returnValue, + df.typeParams, + df.paramLists, + df.comment + ) + } + case vl: Val => transformEntity(vl, _.valTransformation) { vl => + ValImpl( + vl.name, + vl.modifiers, + vl.path, + vl.returnValue, + vl.comment + ) + } + } + + traverse(pack).asInstanceOf[Package] + } + + override def run(implicit ctx: Context): Unit = () + } + + object DocMiniTransformations { + private var previousPhase = 0 + def apply(transformations: DocMiniPhase*) = + new DocMiniTransformations(transformations.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 => id + } + + // Partial functions instead???? + def transformPackage(implicit ctx: Context): PartialFunction[Package, Package] = 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 classTransformation(cls: Class)(implicit ctx: Context) = (transformClass orElse identity)(cls) + private[transform] def cclassTransformation(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) + } +} |