-
-
Save mbloms/1aab9ac35b955bdc57a60a93c15d1c0b to your computer and use it in GitHub Desktop.
A Scala compiler plugin that creates a new class in a different (fresh) package
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package scala.plugin | |
import scala.tools.nsc | |
import nsc.Global | |
import nsc.Phase | |
import nsc.plugins.Plugin | |
import nsc.plugins.PluginComponent | |
import nsc.transform.{ Transform, TypingTransformers } | |
import nsc.symtab.Flags | |
import scala.tools.nsc.transform.TypingTransformers | |
class PackagePlugin(val global: Global) extends Plugin { | |
import global._ | |
val name = "Class in new Package" | |
val description = "" | |
val components = List[PluginComponent](ExampleComponent) | |
// a sample component which is a transformer | |
// which replaces all literal string constants | |
// in the compiled sources | |
private object ExampleComponent extends PluginComponent with TypingTransformers with Transform { | |
import global._ | |
import global.definitions._ | |
val global = PackagePlugin.this.global | |
// TODO: change that according to your requirements | |
override val runsAfter = List("uncurry") | |
/** | |
* The phase name of the compiler plugin | |
* @todo Adapt to specific plugin. | |
*/ | |
val phaseName = "Class in new Package" | |
def newTransformer(unit: CompilationUnit) = new PackageTransformer(unit) | |
var additionalClasses: List[Tree] = Nil | |
lazy val pkg = mkTopLevelPackage("mypackage") | |
/** Create a new package symbol inside the empty (default) package. Takes | |
* care of wiring the module, module class and their types. */ | |
def mkTopLevelPackage(name: String): Symbol = { | |
val pkg = definitions.EmptyPackageClass.newPackage(NoPosition, newTermName(name)) | |
pkg.moduleClass setInfo ClassInfoType(Nil, new Scope, pkg.moduleClass) | |
pkg.setInfo(pkg.moduleClass.tpe) | |
pkg | |
} | |
class PackageTransformer(unit: CompilationUnit) extends TypingTransformer(unit) { | |
override def transform(tree: Tree): Tree = tree match { | |
case PackageDef(n @ Ident(nme.EMPTY_PACKAGE_NAME), stats) => | |
// copied from the super class, the currentOwner needs to be maintained when recursing | |
val stats1 = atOwner(tree.symbol.moduleClass)(transformStats(stats, currentOwner)) | |
val pkgTree = PackageDef(Ident(pkg), additionalClasses).setSymbol(pkg) | |
println("Adding %d classes".format(additionalClasses.length)) | |
treeCopy.PackageDef(tree, n, stats1 ++ Seq(localTyper.typed(pkgTree))) | |
case Literal(Constant("spring")) => | |
val sym = pkg.moduleClass.newClass(tree.pos, newTypeName("MyClass")) | |
sym.setInfo(ClassInfoType(List(definitions.AnyRefClass.typeConstructor), new Scope, sym)) | |
val clsDef = ClassDef(sym, | |
Modifiers(sym.flags), | |
Nil, // no class parameters | |
List(Nil), // no arguments to the super class | |
Nil, // no body | |
NoPosition) | |
additionalClasses ::= localTyper.typed(clsDef) | |
tree | |
// don't forget this case, so that tree is actually traversed | |
case _ => super.transform(tree) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment