【问题标题】:Access code file and line number from Scala macro?从 Scala 宏访问代码文件和行号?
【发布时间】:2014-04-24 06:03:34
【问题描述】:

如何在 Scala 宏中访问代码文件的名称和行号?我查看了SIP-19,它说可以使用宏轻松实现...

编辑: 为了澄清,我想要调用者的代码文件和行号。我已经有一个debug macro,我想修改它以打印调用debug的人的行号和文件名

【问题讨论】:

    标签: scala reflection scala-2.10 scala-macros scala-2.11


    【解决方案1】:

    你想要c.macroApplication.pos,其中c代表Context

    c.enclosingPosition 在堆栈上找到最近的有位置的宏。 (请参阅其他答案。)例如,如果您的断言宏为 F"%p: $msg" 生成树但未分配位置,则 F 宏将是无位置的。

    来自字符串插值器宏的示例,F"%p"

      /* Convert enhanced conversions to something format likes.
       * %Q for quotes, %p for position, %Pf for file, %Pn line number,
       * %Pc column %Po offset.
       */
      private def downConvert(parts: List[Tree]): List[Tree] = {
        def fixup(t: Tree): Tree = {
          val Literal(Constant(s: String)) = t
          val r = "(?<!%)%(p|Q|Pf|Po|Pn|Pc)".r
          def p = c.macroApplication.pos
          def f(m: Match): String = m group 1 match {
            case "p"  => p.toString
            case "Pf" => p.source.file.name
            case "Po" => p.point.toString
            case "Pn" => p.line.toString
            case "Pc" => p.column.toString
            case "Q"  => "\""
          }
          val z = r.replaceAllIn(s, f _)
          Literal(Constant(z)) //setPos t.pos
        }
        parts map fixup
      }
    

    【讨论】:

      【解决方案2】:

      如果您的意思是源代码中当前位置的文件名和行号,对于 2.10,我对that SO question 的回答就是您要找的:

      def $currentPosition:String = macro _currentPosition
      def _currentPosition(c:Context):c.Expr[String]={ import c.universe._
        val pos = c.enclosingPosition
        c.Expr(Literal(Constant(s"${pos.source.path}: line ${pos.line}, column ${pos.column}")))
      }
      

      这也应该适用于 2.11,尽管这种创建 AST 的方式似乎已被弃用。

      你也可以看看at that excerpt of my project Scart;这就是我使用这种技术发出跟踪以进行调试的方式。

      【讨论】:

      • >$ 其实我知道,但这是故意的:第一反应是“那个不应该是丑陋的东西是什么?”,然后你发现它是一个宏,不管你是初学者或专家。根据我的经验,任何语言的宏都可能引起极大的混乱。作为一名开发人员,我想知道什么是宏,因此这个笨拙但引人注目的技巧 :) 相反,通过使用宏的规范名称,读者认为它只是另一种常规方法/函数;那么当一个序列没有按预期运行时(当然文档还没有准备好),可能会浪费很多时间来查找错误。干杯。
      【解决方案3】:

      “编写 Scala 编译器插件”中的示例显示了如何访问当前位置的行名和当前编号,正如其他答案所提到的那样。

      http://www.scala-lang.org/old/node/140

      除了上面的答案,你还可以从 CompilationUnit 返回的 AST 中获取位置。

      例如:

      def apply(unit: CompilationUnit) {
          // Get the AST
          val tree = unit.body  
      
          // Get the Position
          // Scala.util.parsing.input.Position
          val myPos = tree.pos 
      
          // Do something with the pos
          unit.warning(pos, "Hello world")
      }
      

      【讨论】:

        猜你喜欢
        • 2013-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-14
        • 2017-10-21
        • 1970-01-01
        • 2018-06-27
        • 1970-01-01
        相关资源
        最近更新 更多