Синтаксис AST отражения Scala

Я пытаюсь вручную сгенерировать AST, используя API отражения, используя showRaw, чтобы дать мне некоторые подсказки по требуемому синтаксису. Этот код:

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 ) )

дает необработанный вывод AST:

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

Помещение буквального текста необработанного вывода обратно в программу не будет компилироваться:

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

поскольку Ident, по-видимому, требует String в качестве аргумента. Если я передам строку "myfn", то

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

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

он компилируется, но оценка завершается ошибкой во время выполнения с

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

Следовательно, фактический тип myfn в необработанных выходных данных AST предположительно отличается от String, но из документации API не видно, что это может быть.

Итак, кто-нибудь может сказать мне, как мне создать требуемый AST?


person NietzscheanAI    schedule 12.03.2013    source источник
comment
Если я правильно помню, когда что-то не цитируется в распечатке showRaw, это означает, что в этой позиции есть символ, поэтому вам нужно использовать mirror.staticClass/staticModule, чтобы добраться до него.   -  person Eugene Burmako    schedule 16.03.2013


Ответы (1)


Я сделал это немного по-другому — одна проблема еще и в том, что значение x не известно глобально — поэтому я использовал постоянные значения, которые можно легко заменить. Также я не знаю, определен ли ваш myfn на глобальном уровне относительно вызова eval. Небольшой образец программы теперь работает (однако скомпилирован с новейшей версией 2.10.1-RC3 - ​​может быть, что-то было исправлено?).

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))))))
}

изменить

После комментариев ниже, вот вызов, включающий другой пакет mypackage, который может быть произвольным путем к пакету, содержащим точки:

tb.eval(Apply(
  Select(Select(Ident(newTermName("mypackage")), newTermName("myfn")), newTermName("apply")), 
  List(Literal(Constant(1.0)), Literal(Constant(2.0)))))
person michael_s    schedule 12.03.2013
comment
Получается, что RC3 не нужен и не достаточен, чтобы решить проблему с моей версией: если я перенесу все в пакет по умолчанию, то он заработает. Пока не уверен, что это ошибка, но квалификация с помощью mypackage.myfun не помогает... - person NietzscheanAI; 14.03.2013
comment
Ident(newTermName(mypackage.myfun)) не будет работать, но Select(Ident(newTermName(mypackage)), newTermName(myfun)) должен. - person Eugene Burmako; 16.03.2013
comment
Спасибо - я изменил пост. - person michael_s; 16.03.2013