Skip to content

Instantly share code, notes, and snippets.

@dragos
Created February 11, 2012 00:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dragos/1794246 to your computer and use it in GitHub Desktop.
Save dragos/1794246 to your computer and use it in GitHub Desktop.
A Scala compiler plugin that creates a new class in a different (fresh) package
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