Skip to content

Instantly share code, notes, and snippets.

@squito
Last active January 28, 2016 07:41
Show Gist options
  • Save squito/7094987 to your computer and use it in GitHub Desktop.
Save squito/7094987 to your computer and use it in GitHub Desktop.
code samples to go along w/ a blog post on macros imranrashid.com/posts/learning-scala-macros/
val addedTrait = Select(Select(Select(
Select(Ident(newTermName("com")), newTermName("imranrashid")),
newTermName("oleander")),newTermName("macros")),
newTypeName("SimpleTrait"))
trait SimpleTrait {
def x: Int
def y: Float
}
@FillTraitDefs class Foo extends SimpleTrait {}
trait SomeData {
def x: Int
def y: Float
def z: Float
}
trait OtherData {
def a: Float
def b: Int
}
@ByteBufferBacked(classOf[SomeData]) class SomeDataImpl
@ByteBufferBacked(classOf[OtherData]) class OtherDataImpl
class FillTraitDefs extends StaticAnnotation {
def macroTransform(annottees: Any*) = macro SimpleTraitImpl.addDefs
}
object SimpleTraitImpl {
def addDefs(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
val inputs = annottees.map(_.tree).toList
val newDefDefs = List(
DefDef(Modifiers(), newTermName("x"), List(), List(), TypeTree(), Literal(Constant(5))),
DefDef(Modifiers(), newTermName("y"), List(), List(), TypeTree(), Literal(Constant(7.0f)))
)
val modDefs = inputs map {tree => tree match {
case ClassDef(mods, name, something, template) =>
val q = template match {
case Template(superMaybe, emptyValDef, defs) =>
Template(superMaybe, emptyValDef, defs ++ newDefDefs)
case y =>
y
}
ClassDef(mods, name, something, q)
case x =>
x
}}
val result = c.Expr(Block(modDefs, Literal(Constant())))
result
}
}
class B(bb: ByteBuffer) extends A {
def x = bb.getInt(0)
def y = bb.getFloat(4)
}
val classdef = q"""class Foo extends A with B with C {}"""
val q"class $cname extends $parent with ..$traits { ..$body }" = classdef
scala> q"def x = 5"
res3: reflect.runtime.universe.DefDef = def x = 5
val q"class $ignore extends $addedType" =
q"class Foo extends com.imranrashid.oleander.macros.SimpleTrait"
import language.experimental.macros
import reflect.macros.Context
import scala.annotation.StaticAnnotation
import scala.reflect.runtime.{universe => ru}
import ru._
scala> ru.showRaw{ru.reify{def x = 5}}
res11: String = Expr(Block(List(DefDef(Modifiers(), newTermName("x"), List(), List(), TypeTree(), Literal(Constant(5)))), Literal(Constant(()))))
val newDefDefs = reify {
def x = 5
def y = 7.0f
}.tree match { case Block(defs, _) => defs}
import language.experimental.macros
import reflect.macros.Context
import scala.annotation.StaticAnnotation
import scala.reflect.runtime.{universe => ru}
// AST of defining a val
scala> ru.showRaw{ru.reify{val x = 5}}
res1: String = Expr(Block(List(ValDef(Modifiers(), newTermName("x"), TypeTree(), Literal(Constant(5)))), Literal(Constant(()))))
// AST for defining a class
scala> ru.showRaw{ru.reify{class B}}
res2: String = Expr(Block(List(ClassDef(Modifiers(), newTypeName("B"), List(), Template(List(Ident(newTypeName("AnyRef"))), emptyValDef, List(DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(())))))))), Literal(Constant(()))))
// AST for defining a class with a templated parent -- but showRaw is wrong here!
scala> ru.showRaw{ru.reify{class B extends collection.mutable.Seq[String]}}
res7: String = Expr(Block(List(ClassDef(Modifiers(), newTypeName("B"), List(), Template(List(AppliedTypeTree(Ident(scala.collection.mutable.Seq), List(Select(Ident(scala.Predef), newTypeName("String"))))), emptyValDef, List(DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(())))))))), Literal(Constant(()))))
trait A {
def x: Int
def y: Float
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment