summaryrefslogtreecommitdiff
path: root/moduledefs
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2017-12-30 19:01:03 -0800
committerLi Haoyi <haoyi.sg@gmail.com>2017-12-30 20:35:31 -0800
commit356dca0f92931b07e1a80013aefb025b6a7d7d42 (patch)
tree6517cbd15943361cbd896e64a7007c058f20281d /moduledefs
parente84eff79f6f23b9a6518c74ba137ab4ce1347929 (diff)
downloadmill-356dca0f92931b07e1a80013aefb025b6a7d7d42.tar.gz
mill-356dca0f92931b07e1a80013aefb025b6a7d7d42.tar.bz2
mill-356dca0f92931b07e1a80013aefb025b6a7d7d42.zip
`Core` -> `core`, for consistency with SBT naming schemes
`ScalaPlugin` -> `scalalib`, to avoid confusion with Scala compiler plugins `ScalaModule` -> `module`, to be used via `scalalib.Module`, avoid unnecessary duplication in th name prefix `plugin` -> `moduledefs`, to more accurately describe what it does (since it includes `Cacher` as well)
Diffstat (limited to 'moduledefs')
-rw-r--r--moduledefs/src/main/resources/scalac-plugin.xml4
-rw-r--r--moduledefs/src/main/scala/mill/moduledefs/AutoOverridePlugin.scala58
-rw-r--r--moduledefs/src/main/scala/mill/moduledefs/Cacher.scala33
3 files changed, 95 insertions, 0 deletions
diff --git a/moduledefs/src/main/resources/scalac-plugin.xml b/moduledefs/src/main/resources/scalac-plugin.xml
new file mode 100644
index 00000000..48753a22
--- /dev/null
+++ b/moduledefs/src/main/resources/scalac-plugin.xml
@@ -0,0 +1,4 @@
+<plugin>
+ <name>auto-override-plugin</name>
+ <classname>mill.moduledefs.AutoOverridePlugin</classname>
+</plugin> \ No newline at end of file
diff --git a/moduledefs/src/main/scala/mill/moduledefs/AutoOverridePlugin.scala b/moduledefs/src/main/scala/mill/moduledefs/AutoOverridePlugin.scala
new file mode 100644
index 00000000..5b33abbe
--- /dev/null
+++ b/moduledefs/src/main/scala/mill/moduledefs/AutoOverridePlugin.scala
@@ -0,0 +1,58 @@
+package mill.moduledefs
+
+import scala.reflect.internal.Flags
+import scala.tools.nsc.io.VirtualFile
+import scala.tools.nsc.util.BatchSourceFile
+import scala.tools.nsc.{Global, Phase}
+import scala.tools.nsc.plugins.{Plugin, PluginComponent}
+
+class AutoOverridePlugin(val global: Global) extends Plugin {
+ import global._
+ override def init(options: List[String], error: String => Unit): Boolean = true
+
+ val name = "auto-override-plugin"
+ val description = "automatically inserts `override` keywords for you"
+ val components = List[PluginComponent](
+ new PluginComponent {
+
+ val global = AutoOverridePlugin.this.global
+ import global._
+
+ override val runsAfter = List("typer")
+ override val runsBefore = List("patmat")
+
+ val phaseName = "auto-override"
+
+ override def newPhase(prev: Phase) = new GlobalPhase(prev) {
+
+ def name: String = phaseName
+
+ def isCacher(owner: Symbol) = {
+ val baseClasses =
+ if (owner.isClass) Some(owner.asClass.baseClasses)
+ else if (owner.isModule) Some(owner.asModule.baseClasses)
+ else None
+ baseClasses.exists(_.exists(_.fullName == "mill.moduledefs.Cacher"))
+ }
+
+ def apply(unit: global.CompilationUnit): Unit = {
+ object AutoOverrider extends global.Transformer {
+ override def transform(tree: global.Tree) = tree match{
+ case d: DefDef
+ if d.symbol.overrideChain.count(!_.isAbstract) > 1
+ && !d.mods.isOverride
+ && isCacher(d.symbol.owner) =>
+
+ d.symbol.flags = d.symbol.flags | Flags.OVERRIDE
+ copyDefDef(d)(mods = d.mods | Flags.OVERRIDE)
+ case _ => super.transform(tree)
+
+ }
+ }
+
+ unit.body = AutoOverrider.transform(unit.body)
+ }
+ }
+ }
+ )
+} \ No newline at end of file
diff --git a/moduledefs/src/main/scala/mill/moduledefs/Cacher.scala b/moduledefs/src/main/scala/mill/moduledefs/Cacher.scala
new file mode 100644
index 00000000..cea2ca41
--- /dev/null
+++ b/moduledefs/src/main/scala/mill/moduledefs/Cacher.scala
@@ -0,0 +1,33 @@
+package mill.moduledefs
+
+import scala.collection.mutable
+import scala.reflect.macros.blackbox.Context
+
+
+trait Cacher[C[_]]{
+ private[this] lazy val cacherLazyMap = mutable.Map.empty[sourcecode.Enclosing, C[_]]
+ def wrapCached[T](in: C[T], enclosing: String): C[T]
+ protected[this] def cachedTarget[T](t: => C[T])
+ (implicit c: sourcecode.Enclosing): C[T] = synchronized{
+ cacherLazyMap.getOrElseUpdate(c, wrapCached(t, c.value)).asInstanceOf[C[T]]
+ }
+}
+object Cacher{
+ def impl0[M[_], T: c.WeakTypeTag](c: Context)(t: c.Expr[M[T]]): c.Expr[M[T]] = {
+ c.Expr[M[T]](wrapCached(c)(t.tree))
+ }
+ def wrapCached(c: Context)(t: c.Tree) = {
+
+ import c.universe._
+ val owner = c.internal.enclosingOwner
+ val ownerIsCacherClass =
+ owner.owner.isClass &&
+ owner.owner.asClass.baseClasses.exists(_.fullName == "mill.moduledefs.Cacher")
+
+ if (ownerIsCacherClass && owner.isMethod) q"this.cachedTarget($t)"
+ else c.abort(
+ c.enclosingPosition,
+ "T{} members must be defs defined in a Cacher class/trait/object body"
+ )
+ }
+} \ No newline at end of file