【问题标题】:How can I syntax check a Scala script without executing the script and generating any class files?如何在不执行脚本和生成任何类文件的情况下检查 Scala 脚本的语法?
【发布时间】:2011-03-06 03:18:56
【问题描述】:

可以在 Scala 中编写脚本。所以你可以把它放到 Hello.scala 中

#!/bin/sh
exec scala $0 $@
!#

println("You supplied " + args.length + " arguments!")

并使其在 Unix 中可执行

chmod u+x Hello.scala

然后你可以简单地运行脚本

./Hello.scala

如果没有语法错误,这将编译脚本并运行它。但是,这并没有考虑到我只想执行脚本进行语法检查的情况。我不想修改脚本(即通过删除 #! 指令),也不想生成任何 *.class 文件。

如何检查 Scala 脚本的语法?

【问题讨论】:

  • 只检查语法可能是最简单的方法,方法是使用语言规范中给出的语法使用 ANTLR 等工具创建基本解析器。您也想执行名称和类型检查吗?如果是这样,事情就会变得一团糟,您可能想直接使用(部分)scalac。
  • 我的问题并不准确。我想执行语法检查以及类型检查,并且我想使用 Scala 编译器/基础架构。迈尔斯的回答就在按钮上。
  • 据说scalacheck提供了一个命令行语法检查器scalacheck.org

标签: scala scripting


【解决方案1】:

我希望您实际上想要的不仅仅是检查正确的语法……大概您想知道的是,如果您确实编译了文件,那么您的文件是否会正确编译。这包括类型检查和语法检查。

对于 Scala 源文件(即不是脚本),您可以指定 -Ystop:refchecks 命令行参数以使编译器在开始代码生成之前停止(如果您真的只对语法正确性感兴趣,您可以指定 -Ystop :解析器)。如果有错误,它们会以与完全编译源代码完全相同的方式显示在控制台上。

对于 Scala 脚本,您还可以指定 -Ystop:refchecks 参数。如果您这样做,那么您将看到控制台上报告的编译错误,或者,如果脚本中没有错误,您将看到以下内容,

$ scala -Ystop:refchecks Hello.scala 
java.lang.ClassNotFoundException: Main

ClassNotFoundException 表示没有生成类文件并且您的脚本尚未执行。

【讨论】:

  • 优秀的答案。你的解释是正确的。我想知道如果我确实编译了文件是否可以正确编译。谢谢。
  • 这仍然有效吗?似乎不适用于 scala 2.9。在搜索中找不到任何关于此的信息。谢谢。
  • 在 2.9 中使用 scalac 尝试选项 -Ystop-after:refchecks 而不是 -Ystop:refchecks
【解决方案2】:

如果您想从文件中删除行以传递给解释器,您可以创建一个名为 CutScala.scala(或任何您喜欢的)的脚本:

#!/bin/sh
exec scala $0 $@
!#

import scala.collection.JavaConversions._
import java.io._

val p = new ProcessBuilder(
  List(
    "scala",
    "-e",
    io.Source.fromFile(args(1)).getLines().drop(args(0).toInt).mkString("\n")
  ) :::
  args.drop(2).toList
).start()

p.waitFor

val output = List(p.getInputStream,p.getErrorStream).map(
  x => new BufferedReader(new InputStreamReader(x))
)

println("Exit code = " + p.exitValue)
for ((reader,title) <- (output zip List("Output:","Errors:"))) {
  println(title);
  Iterator.continually(reader.readLine).takeWhile(_!=null).foreach(println)
  println
}

然后像这样称呼它

./CutScala.scala 4 Hello.scala a b c

删除前 4 行并解析其余行。迈尔斯的回答告诉你如何做另一半(更困难的)不产生任何输出和不运行任何东西。

【讨论】:

  • @Elazar Leibovich - 或tail -n+4。问题是 Scala 脚本解释器的 AFAICT 不会采用标准输入,并且您无法避免对命令替换进行标记化,因此将文本填充到 -e 的相对简单的尝试是行不通的。
  • cat $1|awk 'NR &gt;4' &gt;/tmp/tmp.$1 &amp;&amp; scalac /tmp/tmp.$1 ; rm /tmp/tmp.$1 或更复杂的方式来生成唯一文件名以保持完整性。但是这么多用于琐碎任务的代码向我证明,这是完成这项工作的错误工具。还要考虑到您必须遭受两次 JVM 启动时间,对于脚本和 scala
  • @Elazar - 我假设由于 OP 想要生成零类文件(而不是在临时目录中生成它们并删除它们),他也不希望生成其他临时文件。使用临时文件显然很容易。但无论如何,同意,perl 或 awk 或类似的东西更适合快速单行。对我来说,Scala 变得更容易的交叉点通常发生在 5-10 行。
猜你喜欢
  • 2011-05-16
  • 2015-12-05
  • 1970-01-01
  • 2010-09-15
  • 2017-03-02
  • 1970-01-01
  • 1970-01-01
  • 2015-06-12
  • 1970-01-01
相关资源
最近更新 更多