如何判断Scala中的标识符是否无效?

时间:2014-02-26 09:01:46

标签: scala reflection

我想我会在scala-reflect或scala-compiler中找到它,但我无法为此找到一个记录的API。有没有办法在运行时执行此操作?

e.g。 def isValidIdentifer(s:String)

(我对保留关键字的实际列表不感兴趣,我可以自己编写阅读手册)

编辑:

基于@sschaef的答案,附加规范:它应该处理任何类型的输入,如果s是单个有效标识符,则返回true

我尝试扩展这个答案:

import scala.tools.reflect.{ToolBox, ToolBoxError}

lazy val tb = scala.reflect.runtime.universe.runtimeMirror(getClass.getClassLoader).mkToolBox()

def isIdentifier(ident: String): Boolean = {
  if (ident.startsWith(" ") || ident.endsWith(" ")) {
    return false
  }
  try {
    val tree = tb.parse(s"val $ident:Int = 0")
    if (tree.toString().length != ident.length + 13) {
      return false
    }
    tree.children match {
      case c0 :: c1 :: Nil if
      c0.children.isEmpty && c0.productArity == 1 && c0.productElement(0).toString == "Int"
        && c1.children.isEmpty && c1.productArity == 1 && c1.productElement(0).toString == "Constant(0)" => true
      case _ => false
    }

  } catch {
    case _: ToolBoxError => false
  }
}

以下恶意案例成功:b:Intb = 0; cb/*comment*/

1 个答案:

答案 0 :(得分:2)

查看编译器,我发现了这个:

    case 'A' | 'B' | 'C' | 'D' | 'E' |
         'F' | 'G' | 'H' | 'I' | 'J' |
         'K' | 'L' | 'M' | 'N' | 'O' |
         'P' | 'Q' | 'R' | 'S' | 'T' |
         'U' | 'V' | 'W' | 'X' | 'Y' |
         'Z' | '$' | '_' |
         'a' | 'b' | 'c' | 'd' | 'e' |
         'f' | 'g' | 'h' | 'i' | 'j' |
         'k' | 'l' | 'm' | 'n' | 'o' |
         'p' | 'q' | 'r' | 's' | 't' |
         'u' | 'v' | 'w' | 'x' | 'y' | // scala-mode: need to understand multi-line case patterns
         'z' =>
      putChar(ch)
      nextChar()
      getIdentRest()

这是scanner的一部分。此外,请查看解析标识符rest的section。看起来您不能轻易复制或使用代码。

我建议使用工具箱:

scala> import scala.tools.reflect.{ToolBox, ToolBoxError}
import scala.tools.reflect.{ToolBox, ToolBoxError}

scala> val tb = scala.reflect.runtime.universe.runtimeMirror(
    getClass.getClassLoader).mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@6c865bc6

scala> def isIdentifier(ident: String) =
    try { tb.parse(s"val ($ident) = 0"); true }
    catch { case _: ToolBoxError => false }
isIdentifier: (ident: String)Boolean

scala> isIdentifier("hello")
res0: Boolean = true

scala> isIdentifier("hello_-")
res1: Boolean = true

scala> isIdentifier("hello-")
res2: Boolean = false

scala> isIdentifier("`hello-`")
res3: Boolean = true