Skip to content

Instantly share code, notes, and snippets.

@TiarkRompf
Last active November 30, 2017 16:28
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 TiarkRompf/4738132 to your computer and use it in GitHub Desktop.
Save TiarkRompf/4738132 to your computer and use it in GitHub Desktop.
generic class lifting and method forwarders
import language.experimental.macros
import language.dynamics
import scala.reflect.macros._
case class Rep[+T](x:String)
implicit def anyToRep[T](x:T) = new Rep[T](x.toString)
class ShouldLift[T]
def dyncall[A,B,C](rec: Rep[A], name: String, arg: Rep[B]): Rep[C] = new Rep(rec.x + "." + name + " " + arg.x)
type RepContext[T] = Context { type PrefixType = Rep[T] }
def impl[T:c.WeakTypeTag](c:RepContext[T])(name: c.Expr[String])(arg: c.Expr[Rep[Any]])(ev: c.Expr[ShouldLift[T]]): c.Expr[Rep[Any]] = {
import c.universe._
val Literal(Constant(n: String)) = name.tree
val tpe = implicitly[c.WeakTypeTag[T]].tpe
val member = tpe.member(newTermName(n))
if (member != NoSymbol) {
val Apply(TypeApply(call, _), args1) = reify(dyncall[Any,Any,Any](c.prefix.splice,name.splice,arg.splice)).tree
val MethodType(List(pt),rt) = member.typeSignature
c.Expr[Rep[Any]](Apply(TypeApply(call,List(tpe,pt.typeSignature,rt) map (TypeTree(_))), args1))
} else c.abort(c.prefix.tree.pos,"not found: "+n)
}
class LRep[+T](x:String) extends Rep[T](x) with Dynamic {
def applyDynamic(name: String)(arg: Rep[Any])(implicit ev: ShouldLift[T]): Rep[Any] = macro impl[T]
}
// example: lift class Foo
class Foo { def bar(x: Int) = x.toString }
implicit object liftFoo extends ShouldLift[Foo]
val x = new LRep[Foo]("FOO")
x bar 7 // ok, returns Rep[String]
x bar "7" // wrong type
x baz 7 // method not found
/*
scala> class Foo { def bar(x: Int) = x.toString }
defined class Foo
scala> implicit object liftFoo extends ShouldLift[Foo]
defined module liftFoo
scala> val x = new LRep[Foo]("FOO")
x: LRep[Foo] = Rep(FOO)
scala> x bar 7
res25: Rep[String] = Rep(FOO.bar 7)
scala> x bar "7"
<console>:246: error: type mismatch;
found : Rep[String]
required: Rep[Int]
x bar "7"
^
scala> x baz 7
<console>:246: error: not found: baz
x baz 7
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment