Scala “如何打印”的源代码;如果;“中的条件”;然后";

Scala “如何打印”的源代码;如果;“中的条件”;然后";,scala,reflection,macros,scala-macros,Scala,Reflection,Macros,Scala Macros,我想在THEN部分打印IF条件的Scala源代码 示例:如果{2+2中找不到值TermName,您的设置是什么?为了添加依赖项,我使用了SBT交叉编译。我认为在2.11之前没有TermName提取器,但是使用一个防护装置很容易完成同样的任务。你在2点10分吗?是的,我在2点10分。我将引用@Eugene Burmako写给我的话:“我看到你很可能在2.10上遇到了错误,但这些错误或多或少都应该很容易修复。与其使用case Select(u,TermName(“sourceCodeOfCondit

我想在THEN部分打印IF条件的Scala源代码

示例:
如果{2+2<5}那么{println(“我当时在这里是因为:“+sourceCodeOfCondition”)}

现在让我们跳过这一节,问题是:在IF之后如何获得block的源代码

我假设IF应该是一个宏


注意:这个问题是我描述的
{val I=5;List(1,2,3);true}.logValueImpl
对我有效的重新定义版本(根据其他问题)

即时实施,因为我只有一分钟的时间:

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

case class Conditional(conditionCode: String, value: Boolean) {
  def THEN(doIt: Unit) = macro Conditional.THEN_impl
}

object Conditional {
  def sourceCodeOfCondition: String = ???

  def IF(condition: Boolean) = macro IF_impl

  def IF_impl(c: Context)(condition: c.Expr[Boolean]): c.Expr[Conditional] = {
    import c.universe._

    c.Expr(q"Conditional(${ show(condition.tree) }, $condition)")
  }

  def THEN_impl(c: Context)(doIt: c.Expr[Unit]): c.Expr[Unit] = {
    import c.universe._

    val rewriter = new Transformer {
      override def transform(tree: Tree) = tree match {
        case Select(_, TermName("sourceCodeOfCondition")) =>
          c.typeCheck(q"${ c.prefix.tree }.conditionCode")
        case other => super.transform(other)
      }
    }

    c.Expr(q"if (${ c.prefix.tree }.value) ${ rewriter.transform(doIt.tree) }")
  }
}
然后:

object Demo {
  import Conditional._

  val x = 1

  def demo = IF { x + 5 < 10 } THEN { println(sourceCodeOfCondition) }
}
对象演示{
有条件导入_
val x=1
def demo=如果{x+5<10},则{println(sourceCodeOfCondition)}
}
最后:

scala> Demo.demo
Demo.this.x.+(5).<(10)
scala>Demo.Demo

Demo.this.x.+(5)。从2.13开始,您还可以通过包装表达式来完成此操作,这意味着您不必定义自定义的
if
函数:

implicit def debugIf[A]: DebugIf => Unit = { cond: DebugIf =>
  logger.info(s"condition = {}, result = ${cond.result}", cond.code)
}

decorateIfs {
  if (System.currentTimeMillis() % 2 == 0) {
    println("decorateIfs: if block")
  } else {
    println("decorateIfs: else block")
  }
}
通过宏实现:

  def decorateIfs[A: c.WeakTypeTag](a: c.Expr[A])(output: c.Expr[DebugIf => Unit]): c.Expr[A] = {
    def isEmpty(tree: Trees#Tree): Boolean = {
      tree match {
        case Literal(Constant(())) =>
          true
        case other =>
          false
      }
    }

    c.Expr[A] {
      a.tree match {
        // https://docs.scala-lang.org/overviews/quasiquotes/expression-details.html#if
        case q"if ($cond) $thenp else $elsep" =>
          val condSource = extractRange(cond) getOrElse ""
          val printThen = q"$output(DebugIf($condSource, true))"
          val elseThen = q"$output(DebugIf($condSource, false))"

          val thenTree = q"""{ $printThen; $thenp }"""
          val elseTree = if (isEmpty(elsep)) elsep else q"""{ $elseThen; $elsep }"""
          q"if ($cond) $thenTree else $elseTree"
        case other =>
          other
      }
    }
  }

  private def extractRange(t: Trees#Tree): Option[String] = {
    val pos = t.pos
    val source = pos.source.content
    if (pos.isRange) Option(new String(source.drop(pos.start).take(pos.end - pos.start))) else None
  }

  case class DebugIf(code: String, result: Boolean)

非常感谢您的解决方案,不幸的是,我在
案例选择(u,TermName(“sourceCodeOfCondition”)=>
中找不到
值TermName
,您的设置是什么?为了添加依赖项,我使用了SBT交叉编译。我认为在2.11之前没有
TermName
提取器,但是使用一个防护装置很容易完成同样的任务。你在2点10分吗?是的,我在2点10分。我将引用@Eugene Burmako写给我的话:“我看到你很可能在2.10上遇到了错误,但这些错误或多或少都应该很容易修复。与其使用
case Select(u,TermName(“sourceCodeOfCondition”),
只需编写
case Select(u,name)if name==newTermName(“sourceCodeOfCondition”)
,这应该足以让事情顺利进行。”是的,尤金,这很有效!非常感谢你们两位。