26

有人可以提供一个使用当前 scala 演示编译器(即)的最小scala.tools.nsc.interactive.Global示例,它可以完成以下任务吗?

  • 编译单个虚拟源文件(即不在文件系统中,而是在例如 a String
  • 从编译器检索所有阶段的结果信息
  • 将源文件中的更改传播到编译器
  • 可能异步接收更多信息

似乎有很多波动,nsc我找不到最新的小例子。所以我非常感谢你在这里的帮助。

4

3 回答 3

10

好的,一周的 100 赏金仍然没有答案,所以我会自己尝试一下……非常欢迎编辑!

演示编译器的关键类是scala.tools.nsc.interactive.Global. 因此,首先,我们需要创建一个编译器实例。

导入 scala.tools.nsc.interactive.Global
类PresentationCompiler { // 我们希望编译器输出是虚拟的 val target = new VirtualDirectory("", None)
// 需要调整才能使用 // sbt。看到这个问题。 val 设置 = 新设置() // 输出到虚拟目标 settings.outputDirs.setSingleOutput(目标)
// 可以替换为自定义实例 // AbstractReporter 获得控制权。 val 记者 = 新的 ConsoleReporter(设置)
val 编译器 = 新的全局(设置,记者)
... }

对于设置,Abhishek 提供的链接非常有价值。

但现在有趣的部分:

1.编译单个虚拟源文件

要编译一个字符串,可以创建一个BatchSourceFile带有底层的VirtualFile. 该 api 在这里被标记为实验性的,看起来不完整。

def compile(code: String) {
  val source = new BatchSourceFile("<virtual>", code)
  val response = new Response[Unit]
  compiler.askReload(List(source), response)    
  response.get.left.foreach { _ =>
    // success
  }
}

2. 从编译器中检索所有阶段的结果信息

这是棘手的部分。由于编译器的多线程特性以及标志在不同阶段以不同含义重用的事实,不可能一次获得所有内容。基本上,您将不得不求助于APIaskSomething中记录的那种方法。例如:

val tcompletion = new Response[List[global.Member]]      
val pos = compiler.ask(() => new OffsetPosition(source, p))
global.askTypeCompletion(pos, tcompletion)
tcompletion.get(5000).get match {
  case Left(members) => // do something with members
  case Right(e) =>
    e.printStackTrace
}

3. 将源文件中的更改传播到编译器

这是有趣的部分,我想通过这个问题来了解一下。我真的不明白这一点,因为BatchSourceFile它被描述为一个内容不会随着时间而改变的文件。SourceFile所以需要提供自定义实现?为什么不在interactive包装中。我确定我只是没有抓住什么。

所以我现在的解决方案是再次调用 compile 方法。

于 2013-05-22T21:28:09.190 回答
2

下面的链接可能会有所帮助

https://github.com/twitter/util/blob/master/util-eval/src/main/scala/com/twitter/util/Eval.scala

我认为它可以满足您正在寻找的所有要求。:)

于 2013-10-25T05:16:09.203 回答
0

可能不是您正在寻找的东西,但一种方法可能是:

  1. 将要编译的源代码写入临时文件,

  2. 对命令运行编译后缀> output.tmp(*nix) 运算符,该运算符应将编译器输出输出到文件中,

  3. 读取该文件并将其加载到内存中...

  4. 最后你删除两个 tmp 文件。

我希望这不是唯一的解决方案,但如果没有其他可能,至少这应该有效......

于 2013-05-18T05:05:45.123 回答