1
votes

I'm attempting to manually-generate ASTs using the reflection API, using showRaw to give me some hints on the required syntax. This code:

object myfn extends Function2[ Double, Double, Double ] {
    def apply( x : Double, y : Double ) = x + y
}

val x = 0.0
println( showRaw( reify( myfn( x, x ) ).tree ) )

gives the raw AST output:

Apply(Select(Ident(myfn), newTermName("apply")), 
    List(Ident(newTermName("x")), Ident(newTermName("x"))))

Putting the literal text of the raw output back into the program won't compile:

val v = Apply(Select(Ident(myfn), newTermName("apply")), 
    List(Ident(newTermName("x")), Ident(newTermName("x"))))
// ^ doesn't compile

since Ident apparently requires a String as an argument. If I pass in the string "myfn", then

val v = Apply(Select(Ident("myfn"), newTermName("apply")), 
    List(Ident(newTermName("x")), Ident(newTermName("x"))))

runtimeMirror( getClass.getClassLoader ).mkToolBox().eval( v )

it compiles, but the evaluation fails at runtime with

"scala.tools.reflect.ToolBoxError: reflective compilation has failed: 
value apply is not a member of <notype>
[...]

Hence the actual type of myfn in the raw AST output is presumably something other than String, but it's not apparent from the API documentation what it might be.

So, can anyone tell me how I construct the required AST?

1
If I recall correctly, when something isn't quoted in the printout of showRaw, it means that there's a symbol in that position, so you need to use mirror.staticClass/staticModule to get to it. - Eugene Burmako

1 Answers

1
votes

I did it slightly different - one problem is also that the value x is not known globally - so I used constant values which can easily be replaced. Also I don't know if your myfn is defined on a global level relative to the eval call. The small sample program here now works (compiled with the newest 2.10.1-RC3 however - maybe there's been something fixed?).

import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox

object myfn extends Function2[Double, Double, Double] {
  def apply(x: Double, y: Double) = x + y
  def printTree {println(showRaw(reify(myfn(1.0, 2.0)).tree))}
}

object ReflectTest extends App {
  myfn.printTree // prints the tree that is used below - myfn is replaced with "myfn"
  val tb = runtimeMirror(getClass.getClassLoader).mkToolBox()
  println("result = " + tb.eval(Apply(Select(Ident("myfn"), newTermName("apply")), List(Literal(Constant(1.0)), Literal(Constant(2.0))))))
}

edit

After the comments below, here is the call including another package mypackage which may be an arbitrary package-path containing dots:

tb.eval(Apply(
  Select(Select(Ident(newTermName("mypackage")), newTermName("myfn")), newTermName("apply")), 
  List(Literal(Constant(1.0)), Literal(Constant(2.0)))))