2017-12-25 33 views
0

매크로 주석을 만들려고하지만 매개 변수를 전달해야합니다.scalameta 낙원 매크로에 매개 변수 전달

@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 메서드에서 액세스 할 수 없습니다.

스칼라 메타를 사용하여이를 극복하는 가장 쉬운 방법을 가르쳐 주시겠습니까? 두 개의 주석을 사용하는 것에 대해 생각했습니다.

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