2017-12-25 21 views
0

マクロ注釈を作成しようとしていますが、パラメータを渡す必要があります。scalameta paradiseマクロにパラメータを渡す

@ToPojo("p1", "p2") 
case class Entity(a: Int, m: Map[Long, Boolean]) 

上記コードの問題として使用さ

class ToPojo(param1: String, param2: String) extends StaticAnnotation { 
    inline def apply(defn: Any): Any = meta { 
     ... 
    } 
} 

Entity既に注釈とapplydefnようになることであるストリッピング - 従って私はそこからパラメータを取得することができません。 param1param2フィールドは、インライン化されているので、applyメソッドからアクセスできません。

スカラーメタを使用してこれを克服する最も簡単な方法を教えてください。私は2つの注釈を使用することを考えました

@ToPojo 
@ToPojoParams("p1", "p2") 
case class Entity(a: Int, m: Map[Long, Boolean]) 

しかし、それはハッキーと醜いです。

どうもありがとうこのコードがあることを

package scalaworld.macros 

import scala.meta._ 

class Argument(arg: Int) extends scala.annotation.StaticAnnotation { 
    inline def apply(defn: Any): Any = meta { 
    // `this` is a scala.meta tree. 
    println(this.structure) 
    val arg = this match { 
     // The argument needs to be a literal like `1` or a string like `"foobar"`. 
     // You can't pass in a variable name. 
     case q"new $_(${Lit.Int(arg)})" => arg 
     // Example if you have more than one argument. 
     case q"new $_(${Lit.Int(arg)}, ${Lit.String(foo)})" => arg 
     case _ => ??? // default value 
    } 
    println(s"Arg is $arg") 
    defn.asInstanceOf[Stat] 
    } 
} 

注Scalametaツリーとしてthis

あなたが一致How do I pass an argument to the macro annotation?セクションの下ScalaMetaパラダイスの説明で述べたように

答えて

1

名前のついた引数は扱いません。引数が多い場合は、通常の引数と名前付き引数の組み合わせをすべて記述するのは退屈です。だからこのようなものを試してみてください:

package examples 

import scala.collection.immutable 
import scala.meta._ 

class MyMacro(p1: String, p2: Int) extends scala.annotation.StaticAnnotation { 


    inline def apply(defn: Any): Any = meta { 
    val params = Params.extractParams(this) 
    //some implementation 
    ... 
    } 

} 


case class Params(p1: String, p2: Int) { 
    def update(name: String, value: Any): Params = name match { 
    case "p1" => copy(p1 = value.asInstanceOf[String]) 
    case "p2" => copy(p2 = value.asInstanceOf[Int]) 
    case _ => ??? 
    } 
} 

object Params { 
    private val paramsNames = List("p1", "p2") 

    def extractParams(tree: Stat): Params = { 
    val args: immutable.Seq[Term.Arg] = tree.asInstanceOf[Term.New].templ.parents.head.asInstanceOf[Term.Apply].args 

    args.zipWithIndex.foldLeft(Params(null, 0))((acc, argAndIndex) => argAndIndex._1 match { 
     case q"${Lit(value)}" => acc.update(paramsNames(argAndIndex._2), value) 
     case q"${Term.Arg.Named(name, Lit(value))}" => acc.update(name.value, value) 
    }) 
    } 
} 
関連する問題