我正在尝试编写一个宏,它将包装一个函数并从其调用将赋值的值中扣除一个参数.
object TestMacros {
def foo(name: String): String = name.toUpper
def bar = macro barImpl
def barImpl(c: Context): c.Expr[String] = {
import c.universe._
//TODO extract value name (should be baz)
c.Expr[String](Apply(
Select(newTermName("TestMacros"), newTermName("foo")), // Probably wrong, just typed it quickly for demonstration purposes
List(Literal(Constant("test"))))) // Should replace test by value name
}
}
object TestUsage {
val baz = bar // should be BAZ
}
Run Code Online (Sandbox Code Playgroud)
我不知道这是否足够清楚.我已经调查了c.prefix和c.macroApplication而没有成功.我在没有宏天堂编译器插件的情况下使用Scala 2.10.2.
我正在研究一个 Scala 宏,我想将 a 的类型与 aSymbol相匹配List[T],其中 theT是给定的Type。我已经有了类型参数的Type对象T。
很容易得到 的 Type 对象List[_]:
val listType = c.weakTypeOf[List[_]]
Run Code Online (Sandbox Code Playgroud)
有了这个,我已经可以检查 typeSignature
sourceParam.typeSignature match {
case paramType if paramType <:< listType =>
....
}
Run Code Online (Sandbox Code Playgroud)
但是我想用 来检查 paramType List[T],那么我如何制作一个类型,我可以在其中获取List[_]和某个Type对象并使其成为新类型?
当注释的参数是常量时,我获得了成功,例如:
@Annotation(2)
class AnnotatedClass
Run Code Online (Sandbox Code Playgroud)
因为我可以通过以下方式获取宏中的值impl:
c.prefix.tree match {
case Apply(_, List(Literal(Constant(x)))) => x.toInt
}
Run Code Online (Sandbox Code Playgroud)
但是当注释的参数不是常数时,我很难过,比如:
object Obj {val n = 2}
@Annotation(Obj.n)
class AnnotatedClass
Run Code Online (Sandbox Code Playgroud)
在假开始类似这样的问题,我可以匹配c.prefix.tree一次拉出名称Obj和n,但我如何获得的价值Obj.n?
最近我有一个在Scala 3中编写宏的经验。我用于inline简单的函数和引用代码,scala.quoted用于更复杂的操作。
似乎这两个功能都用编译时生成的代码替换了一些运行时代码,但inline有一些限制。
它们之间有什么区别,为什么inline不能到处使用引用代码代替?
这是基本设置:
trait MyProduct[A, B](a: A, b: B)
class X
class Y
class XxY(x: X, y: Y) extends MyProduct(x,y)
Run Code Online (Sandbox Code Playgroud)
我正在尝试检查该MyProduct特征的论据。更具体地说,我想提取一些信息,例如字符串“x”和“y”,它们指示 的哪些字段XxY传递给MyProduct.
重要的是,我需要满足具有相同类型的多个字段的情况,例如class XxYxY(x: X, y1: Y, y2: Y) extends MyProduct3(x, y1, y2),因此从类型参数进行推理是不够的。
我想也许问题是我还没有找到一种方法来为条款extends本身添加符号。我可以找到ClassDeffor XxY,从中我可以提取parents并获取已经构造的类型MyProduct[X,Y]。我还查看了symbol.declarations封闭模块和XxY.<init>函数的 ,以查看是否有可用于查找参数的数据,但这些似乎都没有我正在寻找的信息。
查看封闭模块的树让我认为这些信息可能被删除,而是需要从源代码解析为文本,但我希望有人有更好的解决方案。
从评论中编辑:
作为输入,我有一个Type封闭对象/模块的实例。例如:
trait MyProduct[A, B](a: A, b: B)
class X
class Y
class XxY(x: X, y: Y) extends MyProduct(x,y)
Run Code Online (Sandbox Code Playgroud)
作为输出,我想要一些允许我检查 extends 子句中使用的特征的参数的东西。
假设我有一个宏实现
def testImpl[T](c:Context)(implicit wtt:c.WeakTypeTag[T]):c.Tree = {
import c.universe._
def info(msg: Any) = c.info(c.enclosingPosition, msg.toString, true)
val parameter = wtt.tpe.member(TermName("f")).paramLists(0)(0)
info(parameter.typeSignature)
q"{}"
}
Run Code Online (Sandbox Code Playgroud)
和宏定义
def test[T]:Unit = macro DerivingImpl.testImpl[T]
Run Code Online (Sandbox Code Playgroud)
此宏f在其类型参数中查找函数,并打印有关其第一个参数类型的信息.
现在如果我像这样使用这个宏
trait Trait[A] {
def f(x:A): Int
}
test[Trait[Int]]
Run Code Online (Sandbox Code Playgroud)
我被A打印了.我想得到Int.我理解调用member返回的方法符号没有关于具体应用类型的信息.那么,找到参数的实际类型的正确方法是什么?
谢谢.
目前我正在编写一个scala宏库,我想也可以从java中使用它.
但我想不出一种方法来访问scala宏方法形式的java源代码.我们有什么方法可以使用java中的scala宏方法.
是否有一个 Scala 库可以帮助对写入标准输出的文本进行着色?
这个库应该利用 scala 字符串插值机制。
我正在与外部Java API交互,如下所示:
val obj: SomeBigJavaObj = {
val _obj = new SomeBigJavaObj(p1, p2)
_obj.setFoo(p3)
_obj.setBar(p4)
val somethingElse = {
val _obj2 = new SomethingElse(p5)
_obj2.setBar(p6)
_obj2
}
_obj.setSomethingElse(somethingElse)
_obj
}
Run Code Online (Sandbox Code Playgroud)
基本上,Java API公开了.setXXXX许多返回void和设置内容的方法.我无法控制这些外部POJO.
因此,我想编写一个流畅的buildScala宏来检查对象,并.withXXXX()为每个void setXXXX()返回的方法创建一个builder-pattern类型方法 this:
val obj: SomeBigJavaObj =
build(new SomeBigJavaObj(p1, p2))
.withFoo(p3)
.withBar(p4)
.withSomethingElse(
build(new SomethingElse(p5))
.withBar(p6)
.result()
)
.result()
Run Code Online (Sandbox Code Playgroud)
这可能吗?我知道我无法使用def宏生成新的顶级对象,所以我可以使用类似的人体工程学设置.
假设我Foo在某个库中具有某些特征(或抽象类),该特征通常由用户代码扩展并且需要某些方法numArgs:
trait Foo {
// Number of arguments to the default constructor
def numArgs: Int
}
Run Code Online (Sandbox Code Playgroud)
现在numArgs写起来很简单,但是我想生成的是令人讨厌的样板。我可以通过反射来做到这一点,但是它很丑陋,并且无法移植到其他后端,例如ScalaJS,ScalaNative或GraalVM。
是否可以编写只能应用于Foo(而不是在的每个子类上都需要)我可以应用的宏注释,Foo以便生成该方法?
scala ×10
scala-macros ×10
annotations ×1
builder ×1
macros ×1
scala-2.10 ×1
scala-3 ×1
scalameta ×1