2013-05-08 2 views
4

Я хотел бы использовать макрос, который использует тип, определенный ключевым словом «type». Как мне это сделать?Как объединить программирование типов с Scala Macros

Мой исходный код

import scala.reflect.macros.Context 
import scala.language.experimental.macros 

trait Demo6 { 
    type T 

    def add(param: Any): T = macro Demo6.addImpl[T] 

    def fullAdd(param: Any, toStringBasedOnAST: String): T = { 
    doesSomeThing_and_returnsSomething_OfTypeT 
    } 
    def doesSomeThing_and_returnsSomething_OfTypeT: T //just to allow compilation 
} 

object Demo6 { 
    def addImpl[T: c.WeakTypeTag](c: Context)(param: c.Expr[Any]): c.Expr[T] = { 
    import c.universe._ 
    reify { (c.Expr[Demo6](c.prefix.tree)).splice.fullAdd(param.splice, 
             c.literal(show(param.tree)).splice) } 
    //  ^- type mismatch; found : org.autotdd.scalamacros.Demo6#T 
    //       required: T 
    } 
} 

Я размечена ошибку компилятора в примере. Это довольно ясно, что происходит: тип T определяется ключевым словом не такой же, как тип T, который я передаю в

Вещи, которые я пробовал Существует не много документации еще дальше. Scala-макросы. Раздел в http://docs.scala-lang.org/overviews/macros/overview.html был очень полезен для получения меня до сих пор, но его пример использует уровень класса и общий уровень метода. Я просмотрел код для Expecty и macrocosm, которые относятся к проектам, указанным в документации, но не смогли найти такой код.

+0

Вам нужно использовать тег типа для 'T'? Если нет, вам даже не нужен параметр 'T' для' addImpl' - вы должны использовать 'Typed' и' TypeName ("T") '. –

ответ

4

Ваш код почти правильно, просто измените параметр тип Expr:

val expr = reify { ... } 
c.Expr[T](expr.tree) 

Без reify вы должны вернуть это:

c.Expr[T](Apply(Select(c.prefix.tree, newTermName("fullAdd")), 
       List(param.tree, Literal(Constant(show(param.tree)))))) 

reify создает то же самое, но с параметром неправильного типа.

См. this answer для использования showRaw.

В этом случае:

scala> import reflect.runtime.universe._ 
import reflect.runtime.universe._ 

scala> { 
    | object Demo { def fullAdd(param1: Any, param2: String): String = "result" } 
    | showRaw{ reify { Demo.fullAdd("param1", "param2") } } 
    | } 
res0: String = Expr(Apply(Select(Ident(newTermName("Demo")), newTermName("fullAdd")), List(Literal(Constant("param1")), Literal(Constant("param2"))))) 

Заменить Ident(newTermName("Demo")) с c.prefix.tree, Literal(Constant("param1")) с param.tree и "param2" с show(param.tree), и вы получите результат.

+1

Спасибо: действительно хорошо. Я борюсь с пониманием того, как вы это сделали. Можете ли вы предложить какой-нибудь код, чтобы посмотреть, что мне поможет? –

+0

@StaveEscura: Я обновил свой ответ. – senia

+0

Это действительно хорошая ссылка. Я вижу, что я провожу несколько часов, читая его :) –

Смежные вопросы