Num (i : Int) extends Exp case class Var (s : String) extends Exp case class Add (l : Exp , r : Exp) extends Exp case class Mul (l : Exp , r : Exp) extends Exp Add (Num (1), Mul (Num (2), Var ("i")))
Mul (Num (2), x) => Add (x, x) } val isconst : Exp => Boolean = attr ("isconst") { case Num (_) => true case Var (_) => false case Add (l, r) => isconst (l) && isconst (r) case Mul (l, r) => isconst (l) && isconst (r) } But now we are specifying the names twice!
: String) : c.Expr[T] c is the macro Context methodname is the name of the method to call “foobar”: call a method in the caller’s scope “MyObj.foobar”: call a method of some object “this.foobar”: call a method of the receiver
macro invocation. Search the method body for a value definition whose right-hand side is the macro invocation and return the name from that definition. Otherwise, if the invocation computes the value of the method, return the name of the method. Otherwise, return the name of the macro. If there is no enclosing method, get the enclosing template (class, trait or object). Search the template body for a value definition whose right-hand side is the macro invocation. Otherwise, report an error.
invocation is detected by source code position. Detects zero to two argument lists including type application. It’s easy to extend to more but the current version of dsname uses custom patterns to match. We are trying to generalise. We still have issues with detecting values declared inside closures. . . Non-local returns from methods probably don’t work either. . .
Support for passing other data such as the source position More control over how the data will be passed, not just as the first argument of the first argument list