重写Scala函数的toString的宏注释

重写Scala函数的toString的宏注释,scala,macros,annotations,scala-macros,scalameta,Scala,Macros,Annotations,Scala Macros,Scalameta,如何编写宏注释,该注释在使用中看起来像@named(“+2”)\uU2,并生成: new (Int => Int) { override def toString(): String = "+2" def apply(x: Int): Int = x + 2 } 可以创建返回匿名函数的宏。您没有完全获得所需的语法,似乎@在方法中不起作用 import scala.language.experimental.macros import scala.reflect.macros._

如何编写宏注释,该注释在使用中看起来像
@named(“+2”)\uU2
,并生成:

new (Int => Int) {
  override def toString(): String = "+2"
  def apply(x: Int): Int = x + 2
}

可以创建返回匿名函数的宏。您没有完全获得所需的语法,似乎@在方法中不起作用

import scala.language.experimental.macros
import scala.reflect.macros._

object Named {
  def build[T, R](name: String)(applyFunc: T => R): T => R = macro Named.impl[T, R]

  def impl[T: c.WeakTypeTag, R: c.WeakTypeTag](c: whitebox.Context)(name: c.Expr[String])(applyFunc: c.Expr[T => R]): c.Expr[T => R] = {
    import c.universe._

    val functionType = weakTypeOf[T]
    val resultType = weakTypeOf[R]
    c.Expr[T => R](
      c.typecheck(q"""
        new ($functionType => $resultType) {
          override def toString() = $name
          def apply(x: $functionType): $resultType = $applyFunc(x)
        }
      """))
  }
}
然后使用此宏生成您自己的函数:

class NamedTest {

  @Test
  def testNamed() = {
    val b = Named.build[Int, Int]("+2")(_ + 2)
    assertEquals(4, b(2))
    assertEquals("+2", b.toString)
  }
}

可以创建返回匿名函数的宏。您没有完全获得所需的语法,似乎@在方法中不起作用

import scala.language.experimental.macros
import scala.reflect.macros._

object Named {
  def build[T, R](name: String)(applyFunc: T => R): T => R = macro Named.impl[T, R]

  def impl[T: c.WeakTypeTag, R: c.WeakTypeTag](c: whitebox.Context)(name: c.Expr[String])(applyFunc: c.Expr[T => R]): c.Expr[T => R] = {
    import c.universe._

    val functionType = weakTypeOf[T]
    val resultType = weakTypeOf[R]
    c.Expr[T => R](
      c.typecheck(q"""
        new ($functionType => $resultType) {
          override def toString() = $name
          def apply(x: $functionType): $resultType = $applyFunc(x)
        }
      """))
  }
}
然后使用此宏生成您自己的函数:

class NamedTest {

  @Test
  def testNamed() = {
    val b = Named.build[Int, Int]("+2")(_ + 2)
    assertEquals(4, b(2))
    assertEquals("+2", b.toString)
  }
}
正确的语法是
((:Int)+2):@named(“+2”)
。不幸的是,注释表达式的宏注释不会展开

最简单的就是使用

object Named { 
  def build[T, R](name: String)(applyFunc: T => R): T => R = new (T => R) { 
    override def toString() = name
    def apply(x: T): R = applyFunc(x) 
  }
}
没有任何宏

否则,可以展开表达式上的注释:

build.sbt(关于生成源的sbt文档)

project/build.sbt

project/Generator.scala

annotations/src/main/scala/com/example/annotations/named.scala

helpers/src/main/scala/com/example/helpers/TypedFunctions.scala

在/src/main/scala/com/example/App.scala中

out/target/scala-2.13/src_managed/main/scala/com/example/App.scala(在
sbt之后);project out;clean;compile“

另一个例子是正确的语法是
((:Int)+2):@named(“+2”)
。不幸的是,注释表达式的宏注释不会展开

最简单的就是使用

object Named { 
  def build[T, R](name: String)(applyFunc: T => R): T => R = new (T => R) { 
    override def toString() = name
    def apply(x: T): R = applyFunc(x) 
  }
}
没有任何宏

否则,可以展开表达式上的注释:

build.sbt(关于生成源的sbt文档)

project/build.sbt

project/Generator.scala

annotations/src/main/scala/com/example/annotations/named.scala

helpers/src/main/scala/com/example/helpers/TypedFunctions.scala

在/src/main/scala/com/example/App.scala中

out/target/scala-2.13/src_managed/main/scala/com/example/App.scala(在
sbt之后);project out;clean;compile“


另一个例子是

宏应用于什么类型的对象?Function1(带参数的函数)宏应用于什么类型的对象?Function1(带参数的函数)如果使用
命名。build
您似乎根本不需要
def
宏:
名为{def build[T,R](名称:String)的对象(applyFunc:T=>R):T=>R=new(T=>R){override def toString()=name;def apply(x:T):R=applyFunc(x)}
如果您使用
Named.build
您似乎根本不需要
def
宏:
名为{def build[T,R](名称:String)(applyFunc:T=>R):T=>R=new(T=>R){override def toString()=name;def apply(x:T):R=applyFunc(x)}}
import scala.meta._

object Transformer {
  val getNamedAnnotationParam: PartialFunction[Mod, Lit] = {
    case mod"@named(...${List(List(s: Lit))})" => s
  }

  val isNamedAnnotated: Mod => Boolean = getNamedAnnotationParam.lift(_).isDefined

  def transform(input: String): String = transform(input.parse[Source].get).toString

  def transform(input: Tree): Tree = input.transform {
    case q"package $eref { ..$stats }" =>
      val stats1 = stats.filter {
        case q"import ..${List(importer"annotations.{..$importeesnel}")}" => false
        case _ => true
      }

      q"package $eref { ..$stats1 }"

    case q"$expr: ..@$annotsnel" if annotsnel.exists(isNamedAnnotated) =>
      val annotsnel1 = annotsnel.filterNot(isNamedAnnotated)
      val name = annotsnel.collect(getNamedAnnotationParam).head

      val expr1 = expr match {
        case q"(..$params) => $expr2" =>
          val params1 = params.map {
            case param"..$mods $name: ${Some(tpe)} = $expropt" => 
              param"..$mods $name: ${Some(tpe)} = $expropt"
            case param"..$mods $name: ${None} = $expropt" => 
              param"..$mods $name: scala.Any = $expropt"
          }

          val domain = params1.map {
            case param"..$mods $name: $tpeopt = $expropt" => tpeopt.get
          }

          q"""
               val typed = com.example.helpers.${Term.Name("TypedFunction" + params.length)}($expr)

               new ((..$domain) => typed.CoDomain) {
                 override def toString(): String = $name
                 def apply(..$params1): typed.CoDomain = $expr2
               }
             """

        case e => e
      }

      if (annotsnel1.nonEmpty)
        q"$expr1: ..@$annotsnel1"
      else q"$expr1"
  }
}
package com.example.annotations

import scala.annotation.StaticAnnotation

class named(name: String) extends StaticAnnotation
package com.example.helpers

sealed trait TypedFunctions[_CoDomain] {
  type CoDomain = _CoDomain
}

case class TypedFunction0[_CoDomain](f: () => _CoDomain) extends TypedFunctions[_CoDomain]
case class TypedFunction1[_Domain,  _CoDomain](f: _Domain => _CoDomain) extends TypedFunctions[_CoDomain]
case class TypedFunction2[_Domain1, _Domain2,  _CoDomain](f: (_Domain1, _Domain2) => _CoDomain) extends TypedFunctions[_CoDomain]
case class TypedFunction3[_Domain1, _Domain2, _Domain3, _CoDomain](f: (_Domain1, _Domain2, _Domain3) => _CoDomain) extends TypedFunctions[_CoDomain]
package com.example

import annotations.named

object App {
  (((x: Int) => x + 2): @named("+2"))

  (((x: Int, y: Int) => x + y): @named("+"))
}
package com.example
object App {
  {
    val typed = com.example.helpers.TypedFunction1 { (x: Int) => x + 2 }
    new (Int => typed.CoDomain) {
      override def toString(): String = "+2"
      def apply(x: Int): typed.CoDomain = x + 2
    }
  }
  {
    val typed = com.example.helpers.TypedFunction2 { (x: Int, y: Int) => x + y }
    new ((Int, Int) => typed.CoDomain) {
      override def toString(): String = "+"
      def apply(x: Int, y: Int): typed.CoDomain = x + y
    }
  }
}