Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Macro-powered structural types
import scala.annotation.StaticAnnotation
import scala.reflect.macros.Macro
import language.experimental.macros
class body(tree: Any) extends StaticAnnotation
trait Macros extends Macro {
import c.universe._
def selFieldImpl = {
val field = c.macroApplication.symbol
val bodyAnn = field.annotations.filter(_.tpe <:< typeOf[body]).head
bodyAnn.scalaArgs.head
}
def mkObjectImpl(xs: c.Tree*) = {
val kvps = xs.toList map { case q"${_}(${Literal(Constant(name: String))}).->[${_}]($value)" => name -> value }
val fields = kvps map { case (k, v) => q"@body($v) def ${TermName(k)} = macro Macros.selFieldImpl" }
q"class Workaround { ..$fields }; new Workaround{}"
}
}
object mkObject {
def apply(xs: Any*) = macro Macros.mkObjectImpl
}
=================
object Test {
def main(args: Array[String]) = {
val foo = mkObject("x" -> "2", "y" -> 3)
println(foo.x)
println(foo.y)
// println(foo.z) => will result in a compilation error
}
}
Owner

xeno-by commented Jul 10, 2013

No reflection involved!

18:37 ~/Projects/Kepler_structural/sandbox (topic/structural)$ scalac Macros.scala && scalac Test.scala -Xprint:cleanup
[[syntax trees at end of                   cleanup]] // Test.scala
package <empty> {
  object Test extends Object {
    def main(args: Array[String]): Unit = {
      val foo: Object = {
        {
          new anonymous class anon$1()
        }
      };
      scala.this.Predef.println("2");
      scala.this.Predef.println(scala.Int.box(3))
    };
    def <init>(): Test.type = {
      Test.super.<init>();
      ()
    }
  };
  class Test$Workaround$1 extends Object {
    def <init>(): Test$Workaround$1 = {
      Test$Workaround$1.super.<init>();
      ()
    }
  };
  final class anon$1 extends Test$Workaround$1 {
    def <init>(): anonymous class anon$1 = {
      anon$1.super.<init>();
      ()
    }
  }
}

 // compileLateSynthetic-fbb25380ed1946c68a1246b286a54476.scala
package scala.reflect.macros.synthetic {
  class MacrosInvoker extends Object with Macros {
    def selFieldImpl(): reflect.macros.Universe$TreeContextApi = Macros$class.selFieldImpl(MacrosInvoker.this);
    def mkObjectImpl(xs: Seq): reflect.macros.Universe$TreeContextApi = Macros$class.mkObjectImpl(MacrosInvoker.this, xs);
    <paramaccessor> private[this] val c: reflect.macros.Context = _;
    <stable> <accessor> <paramaccessor> def c(): reflect.macros.Context = MacrosInvoker.this.c;
    def <init>(c: reflect.macros.Context): scala.reflect.macros.synthetic.MacrosInvoker = {
      MacrosInvoker.this.c = c;
      MacrosInvoker.super.<init>();
      Macros$class./*Macros$class*/$init$(MacrosInvoker.this);
      ()
    }
  }
}

warning: there were 2 feature warning(s); re-run with -feature for details
one warning found
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment