scala - How to determine if an expression passed to a macro will always result in the same value? -


let's suppose i've defined macro below. types expression of type t , returns object of type mytype[t] (the actual types involved don't matter).

object mymacro {   def macroimpl[t : context.weaktypetag, u : context.weaktypetag](context : scala.reflect.macros.blackbox.context) (expression : context.expr[t]) : context.expr[u] = }  object myobj {   def callmacro[t](expression : t) : mytype[t] = macro mymacro.macroimpl[t, mytype[t]] } 

in macro, i'd determine if expression passed constant or not. mean, want know if expression, once evaluated @ runtime, ever subsequently evaluate different value. if constant, can apply optimizations useful.

i know expression constant if is:

  • a literal expression.
  • a 'this' expression.
  • a reference val or parameter.
  • a member invocation object expression constant, , member being invoked val or lazy val.

for example, expressions passed in first 5 calls callmacro below should considered constant:

class myclass {   val = 0    val myliteral = callmacro("hi!") //constant - literal expression    val mythis = callmacro(this) //constant - expression    val myint = callmacro(i) //constant - reference val    def mymethod(p : myotherclass) {     val myparameter = callmacro(p) //constant - reference parameter     val myvalmember = callmacro(p.x) //constant - invocation of val member     val myvarmember = vallmacro(p.y) //not constant - invocation of var member     val myvarmember = vallmacro(p.z) //not constant - invocation of def member   } }  class myotherclass(val x : int, var y : int) {   def z = x + y } 

i've implemented code first 2 cases (which rather trivial).

def isconstant[t](context : scala.reflect.macros.blackbox.context) (expression : context.expr[t]) = {   import context.universe._     expression.tree match {       case this(_) =>         true       case literal(_) =>         true       /*...put additional cases here...*/       case _ =>         false   } } 

however, i'm not sure whether exists, or if possible detect whether member being called on object val or not.

is possible implement fourth criteria? or, exist in api?

i figured out solution. boiled down me not knowing symbols in scale's reflection system.

i ended adding fifth criteria handle case in implicit parameter or object referenced.

implicit class extendsymbol(symbol : scala.reflect.macros.blackbox.context#symbol) {   def isstable =     (symbol.isterm && symbol.asterm.isstable) || (symbol.ismethod && symbol.asmethod.isstable) }  def isconstant[t](context : scala.reflect.macros.blackbox.context) (tree : context.tree) : boolean = {   import context.universe._   tree match {     case this(_) =>       true     case literal(_) =>       true     case ident @ ident(_) =>       ident.symbol.isstable     case select @ select(objexpr, term) =>       isconstant(context) (objexpr) && select.symbol.isstable     //for implicit values     case apply(typeapply(select(select(this(typename("scala")), termname("predef")), termname("implicitly")), _), _) =>       true     case _ =>       false   } } 

Comments

Popular posts from this blog

yii2 - Yii 2 Running a Cron in the basic template -

asp.net - 'System.Web.HttpContext' does not contain a definition for 'GetOwinContext' Mystery -

mercurial graft feature, can it copy? -