标签: scala-macros

如何在Quasiquote中使用Shapeless?

我试图调用Shapeless从内宏quasiquoteScala,我没有得到什么,我想获得.

我的宏不会返回任何错误,但它不会扩展Witness(fieldName)Witness.Lt[String]

val implicits = schema.fields.map { field =>
  val fieldName:String = field.name
  val fieldType = TypeName(field.valueType.fullName)
  val in = TermName("implicitField"+fieldName)
  val tn = TermName(fieldName)
  val cc = TermName("cc")
  q"""implicit val $in = Field.apply[$className,$fieldType](Witness($fieldName), ($cc:   $className) => $cc.$tn)"""
}
Run Code Online (Sandbox Code Playgroud)

这是我的Field定义:

sealed abstract class Field[CC, FieldName] {
  val  fieldName: String
  type fieldType

  // How to extract this field
  def  get(cc : CC) : fieldType
}

object Field {
  // fieldType …
Run Code Online (Sandbox Code Playgroud)

scala shapeless scala-macros scala-quasiquotes

272
推荐指数
1
解决办法
6966
查看次数

从宏中获取具有匿名类方法的结构类型

假设我们要编写一个定义具有某些类型成员或方法的匿名类的宏,然后创建该类的实例,该类通过这些方法静态地键入为结构类型等.这可以通过2.10中的宏系统实现. 0,类型成员部分非常容易:

object MacroExample extends ReflectionUtils {
  import scala.language.experimental.macros
  import scala.reflect.macros.Context

  def foo(name: String): Any = macro foo_impl
  def foo_impl(c: Context)(name: c.Expr[String]) = {
    import c.universe._

    val Literal(Constant(lit: String)) = name.tree
    val anon = newTypeName(c.fresh)

    c.Expr(Block(
      ClassDef(
        Modifiers(Flag.FINAL), anon, Nil, Template(
          Nil, emptyValDef, List(
            constructor(c.universe),
            TypeDef(Modifiers(), newTypeName(lit), Nil, TypeTree(typeOf[Int]))
          )
        )
      ),
      Apply(Select(New(Ident(anon)), nme.CONSTRUCTOR), Nil)
    ))
  }
}
Run Code Online (Sandbox Code Playgroud)

(提供我方法ReflectionUtils便利特性在哪里constructor.)

这个宏允许我们将匿名类的类型成员的名称指定为字符串文字:

scala> MacroExample.foo("T")
res0: AnyRef{type T = Int} = $1$$1@7da533f6
Run Code Online (Sandbox Code Playgroud)

请注意,它是适当的键入.我们可以确认一切都按预期工作:

scala> implicitly[res0.T =:= Int] …
Run Code Online (Sandbox Code Playgroud)

macros scala structural-typing scala-2.10 scala-macros

182
推荐指数
1
解决办法
8576
查看次数

记录Scala 2.10宏

我将从一个例子开始.这里的List.fill元组与Scala 2.10中的宏相当:

import scala.language.experimental.macros
import scala.reflect.macros.Context

object TupleExample {
  def fill[A](arity: Int)(a: A): Product = macro fill_impl[A]

  def fill_impl[A](c: Context)(arity: c.Expr[Int])(a: c.Expr[A]) = {
    import c.universe._

    arity.tree match {
      case Literal(Constant(n: Int)) if n < 23 => c.Expr(
        Apply(
          Select(Ident("Tuple" + n.toString), "apply"),
          List.fill(n)(a.tree)
        )
      )
      case _ => c.abort(
        c.enclosingPosition,
        "Desired arity must be a compile-time constant less than 23!"
      )
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我们可以使用以下方法:

scala> TupleExample.fill(3)("hello")
res0: (String, String, String) = (hello,hello,hello)
Run Code Online (Sandbox Code Playgroud)

这个家伙在几个方面都是一只奇怪的鸟.首先,arity参数必须是一个文字整数,因为我们需要在编译时使用它.在Scala的早期版本中,(根据我所知),方法甚至无法判断其中一个参数是否是编译时文字.

其次, …

documentation macros scala scala-2.10 scala-macros

72
推荐指数
1
解决办法
2311
查看次数

静态返回类型的Scala宏

所以我有这个宏:

import language.experimental.macros
import scala.reflect.macros.Context

class Foo
class Bar extends Foo { def launchMissiles = "launching" }

object FooExample {
  def foo: Foo = macro foo_impl
  def foo_impl(c: Context): c.Expr[Foo] =
    c.Expr[Foo](c.universe.reify(new Bar).tree)
}
Run Code Online (Sandbox Code Playgroud)

我已经说了三次我想要foo返回一个Foo,但我可以做以下(在2.10.0-RC3中):

scala> FooExample.foo
res0: Bar = Bar@4118f8dd

scala> res0.launchMissiles
res1: String = launching
Run Code Online (Sandbox Code Playgroud)

如果我删除任何一个上的类型参数,也会发生同样的事情c.Expr.如果我真的想确保无论谁打电话foo都看不到他们正在获得Bar,我必须在树本身添加类型归属.

这实际上非常棒 - 例如,我可以将宏指向某种类型的模式,并Vocabulary使用表示词汇表中的术语的成员方法创建某个类的匿名子类,这些将在返回的对象上可用.

我想知道我到底在做什么,所以我有几个问题.首先,该foo方法实际上的返回类型是什么?它是否仅适用于(可选)文档?它明确地约束了返回类型(例如,Int在这种情况下我无法将其更改为),如果我将其完全删除,则会出现如下错误:

scala> FooExample.foo
<console>:8: error: type mismatch;
 found   : Bar
 required: Nothing
              FooExample.foo …
Run Code Online (Sandbox Code Playgroud)

macros types scala scala-2.10 scala-macros

41
推荐指数
1
解决办法
3537
查看次数

我在哪里可以学习为Scala宏构建AST?

在哪里我可以学习如何构建Scala的宏生成的AST?

Scaladoc不像我想的那样有用.例如:

abstract def Apply(sym: Universe.Symbol, args: Universe.Tree*): Universe.Tree
A factory method for Apply nodes.
Run Code Online (Sandbox Code Playgroud)

但是我如何弄清楚Apply节点是什么?我在哪里可以找到AST的节点类型列表,以及它们如何组合在一起?

macros scala scala-macros

39
推荐指数
2
解决办法
4370
查看次数

在Scala中对密封特性进行迭代?

我只是想知道是否有可能在Scala中迭代密封的特征?如果没有,为什么不可能?由于特性是密封的,应该可以吗?

我想做的是这样的:

sealed trait ResizedImageKey {

  /**
   * Get the dimensions to use on the resized image associated with this key
   */
  def getDimension(originalDimension: Dimension): Dimension

}

case class Dimension(width: Int,  height: Int)

case object Large extends ResizedImageKey {
  def getDimension(originalDimension: Dimension) = Dimension(1000,1000)
}

case object Medium extends ResizedImageKey{
  def getDimension(originalDimension: Dimension) = Dimension(500,500)
}

case object Small extends ResizedImageKey{
  def getDimension(originalDimension: Dimension) = Dimension(100,100)
}
Run Code Online (Sandbox Code Playgroud)

通过给枚举值赋予实现,我可以用Java完成.Scala中有同等的东西吗?

enumeration scala sealed scala-macros

38
推荐指数
3
解决办法
1万
查看次数

如何让IntelliJ IDEA识别由宏创建的代码?

背景

我有一个使用了SBT管理斯卡拉项目通常SBT项目布局斯卡拉用宏,即项目,包含宏的主要项目,是实际应用和依赖于宏观子项目子项目.宏是宏注释,实质上是为常规类生成伴随对象.生成的伴随对象在其他成员中声明了apply/unapply方法.

我使用sbt-idea插件生成相应的IntelliJ IDEA项目,并使用IDEA的sbt-plugin中的sbt控制台来编译和运行我的Scala应用程序.

一切都或多或少都有效,除了生成的伴随对象,更重要的是它们的成员,如apply/unapply,IDEA无法识别.因此,我在任何地方都得到了一条波浪线,例如,一种应用方法.

我的设置是IntelliJ IDEA CE 133.471,在Windows 7 x64上使用插件SBT 1.5.1和Scala 0.28.363.

问题

如何让IntelliJ IDEA识别由Scala宏生成的代码(类,对象,方法......)(准确地说是宏注释)?

是否已知其他IDE(例如Eclipse)在这样的设置中工作得更好?

有关

这个问题(不太详细)基本上问了同样的问题,但还没有得到答复(2014-02-26).

根据JetBrains开发人员说法,我要求的功能是他们的长期待办事项清单,但不会很快实施(2014-03-05).

compilation syntax-highlighting intellij-idea scala-macros

38
推荐指数
1
解决办法
2167
查看次数

Scala宏和JVM的方法大小限制

我正在用Scala宏替换Java程序中的一些代码生成组件,并且运行Java虚拟机对单个方法生成的字节代码大小的限制(64千字节).

例如,假设我们有一个大型的XML文件,它表示我们想要在程序中使用的从整数到整数的映射.我们希望避免在运行时解析此文件,因此我们将编写一个宏,它将在编译时进行解析并使用该文件的内容来创建方法的主体:

import scala.language.experimental.macros
import scala.reflect.macros.Context

object BigMethod {
  // For this simplified example we'll just make some data up.
  val mapping = List.tabulate(7000)(i => (i, i + 1))

  def lookup(i: Int): Int = macro lookup_impl
  def lookup_impl(c: Context)(i: c.Expr[Int]): c.Expr[Int] = {
    import c.universe._

    val switch = reify(new scala.annotation.switch).tree
    val cases = mapping map {
      case (k, v) => CaseDef(c.literal(k).tree, EmptyTree, c.literal(v).tree)
    }

    c.Expr(Match(Annotated(switch, i.tree), cases))
  }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,编译的方法将超过大小限制,但不是一个很好的错误说,我们给了一个巨大的堆栈跟踪与大量的调用,TreePrinter.printSeq并被告知我们已经杀死了编译器.

我有一个解决方案,涉及将案例拆分为固定大小的组,为每个组创建一个单独的方法,并添加一个顶级匹配,将输入值调度到适当的组的方法.它可以工作,但它很不愉快,而且我不想每次编写宏时都不必使用这种方法,其中生成的代码的大小取决于某些外部资源.

有没有更清洁的方法来解决这个问题?更重要的是,有没有办法更优雅地处理这种编译器错误?我不喜欢库用户得到一个难以理解的"该条目似乎已经杀死编译器"错误消息的想法只是因为宏正在处理的某些XML文件已超过一些(相当低的)大小阈值.

java macros jvm scala scala-macros

35
推荐指数
2
解决办法
1662
查看次数

Scala Macros:使用Scala中的类字段制作地图

假设我有很多类似的数据类.这是一个示例类User,定义如下:

case class User (name: String, age: Int, posts: List[String]) {
  val numPosts: Int = posts.length

  ...

  def foo = "bar"

  ...
}
Run Code Online (Sandbox Code Playgroud)

我感兴趣的是自动创建一个方法(在编译时),Map该方法以在运行时调用每个字段名称时将其映射到其值的方式返回.对于上面的例子,让我们说我的方法被调用toMap:

val myUser = User("Foo", 25, List("Lorem", "Ipsum"))

myUser.toMap
Run Code Online (Sandbox Code Playgroud)

应该回来

Map("name" -> "Foo", "age" -> 25, "posts" -> List("Lorem", "Ipsum"), "numPosts" -> 2)
Run Code Online (Sandbox Code Playgroud)

你会如何用宏来做到这一点?

这就是我所做的:首先,我创建了一个Model类作为我所有数据类的超类,并在那里实现了这样的方法:

abstract class Model {
  def toMap[T]: Map[String, Any] = macro toMap_impl[T]
}

class User(...) extends Model {
  ...
}
Run Code Online (Sandbox Code Playgroud)

然后我在一个单独的Macros对象中定义了一个宏实现: …

scala case-class scala-macros

33
推荐指数
2
解决办法
8762
查看次数

在Scala中匹配函数文字与quasiquotes

这个问题与我之前的问题的动机相似(虽然它是关于我在不同背景下遇到的问题).

在没有quasiquotes的情况下,我可以非常轻松地在函数文字上进行模式匹配:

import scala.reflect.macros.Context
import scala.language.experimental.macros

object QQExample {
  def funcDemo(f: Int => String) = macro funcDemo_impl
  def funcDemo_impl(c: Context)(f: c.Expr[Int => String]) = {
    import c.universe._

    f.tree match {
      case Function(ps, body) => List(ps, body) foreach println
      case _ => c.abort(
        c.enclosingPosition,
        "Must provide a function literal."
      )
    }

    c.literalUnit
  }
}
Run Code Online (Sandbox Code Playgroud)

其工作方式如下:

scala> QQExample.funcDemo((a: Int) => a.toString)
List(val a: Int = _)
a.toString()
Run Code Online (Sandbox Code Playgroud)

现在假设我想使用quasiquotes更灵活地进行相同类型的匹配.以下内容也将匹配该功能,并打印出我们期望的内容.

case q"($x: $t) => $body" => List(x, t, body) foreach …
Run Code Online (Sandbox Code Playgroud)

macros scala scala-macros scala-quasiquotes

27
推荐指数
1
解决办法
2599
查看次数