Подъемная струна со Скаламетой

Я хотел бы внедрить метод 'toCSV' для анализа класса в CSV String. Моя функция принимает два параметра:

  • Seq [String]: заголовок
  • Seq[Seq[Any]]: поля

Мой макрос:

class model extends scala.annotation.StaticAnnotation {

  inline def apply(defn: Any): Any = meta {
    defn match {
      case cls @ Defn.Class(_, _, _, Ctor.Primary(_, _, paramss), template) =>

        def createToCSV(paramss: Seq[Seq[Term.Param]]): Defn.Def = {

          val names = paramss.flatten.map(param => param.name.syntax)
          val fields = paramss.map(_.map(param => Term.Name(param.name.value)))

          q"""def toCSV =
             CSVTools.toCSV(Seq(...$names), Seq(Seq(...$fields)))"""
        }

        val toCSVImpl = createToCSV(paramss)

        val templateStats: Seq[Stat] = toCSVImpl +: template.stats.getOrElse(Nil)
        cls.copy(templ = template.copy(stats = Some(templateStats)))
      case _ =>
        println(defn.structure)
        abort("@model must annotate a class.")
    }
  }
}

Переменная Term представляет собой Seq [String], а синтаксис квазиквот принимает только Term. Следовательно, ошибка ниже произошла:

[error] /home/xxxxx/intellij/workspace/heroes-scala-meta/macros/src/main/scala/examples/model.scala:18: type mismatch when unquoting;
[error]  found   : scala.collection.immutable.Seq[String]
[error]  required: scala.collection.immutable.Seq[scala.collection.immutable.Seq[scala.meta.Term.Arg]]
[error]              CSVTools.toCSV(Seq(...$names), Seq(Seq(...$fields)))"""
[error]                                    ^
[error] one error found
[error] (macros/compile:compileIncremental) Compilation failed

У тебя есть решение?

Заранее спасибо,

1 ответ

Решение

Это, вероятно, немного странно, но, похоже, работает: явно сопоставьте names для строковых литералов

class model extends scala.annotation.StaticAnnotation {

  inline def apply(defn: Any): Any = meta {
    defn match {
      case cls@Defn.Class(_, _, _, Ctor.Primary(_, _, paramss), template) =>

        def createToCSV(paramss: Seq[Seq[Term.Param]]): Defn.Def = {

          val names: Seq[String] = paramss.flatten.map(param => param.name.syntax)
          val fields = paramss.map(_.map(param => Term.Name(param.name.value)))

          val nameLiterals: Seq[Lit.String] = names.map(n => q"$n".asInstanceOf[Lit.String])

          q"""def toCSV =
              CSVTools.toCSV(scala.collection.immutable.Seq(..$nameLiterals),
                             scala.collection.immutable.Seq(scala.collection.immutable.Seq(...$fields)))"""
        }

        val toCSVImpl = createToCSV(paramss)

        val templateStats: Seq[Stat] = toCSVImpl +: template.stats.getOrElse(Nil)
        cls.copy(templ = template.copy(stats = Some(templateStats)))
      case _ =>
        println(defn.structure)
        abort("@model must annotate a class.")
    }
  }
}
Другие вопросы по тегам