【问题标题】:Scala.js Runtime Compilation to JavascriptScala.js 运行时编译为 Javascript
【发布时间】:2017-08-08 15:49:42
【问题描述】:

大家好。我想弄清楚如何在运行时使用 Scala.js 工具将 Scala 表达式编译为 Javascript。以下是一个简化的设置,作为示例。

比如说,我们有一个简单的 DSL,它由 Ctx => Boolean 函数和对它们的布尔运算组成,如下所示:

implicit class Simple[Ctx](f: Ctx => Boolean) {
  def &&(g: Ctx => Boolean): Ctx => Boolean = ctx => f(ctx) && g(ctx)
  def ||(g: Ctx => Boolean): Ctx => Boolean = ctx => f(ctx) || g(ctx)
  def unary_!: Ctx => Boolean = ctx => !f(ctx)
}

假设我们有一些“构建块”硬编码、编译成 Javascript 并导出,如下所示:

@ExportJSTopLevel("foo") def foo[Ctx](ctx: Ctx): Boolean = ???
@ExportJSTopLevel("bar") def bar[Ctx](ctx: Ctx): Boolean = ???
// and so on

现在可以将这些构建块组合成简单的布尔表达式,例如:foo && barfoo || !bar 等。

假设一些持久实体是在运行时创建的,它们的主体是这样的表达式。我希望能够将它们编译为 Javascript,作为与上面的构建块具有相同签名的函数,这些构建块调用这些构建块。

我在网上找到了几个关于 Scala.js 工具中某个名为 ScalaJSOptimizer 的神秘类的引用。但是,提供给该类的链接总是被破坏或显示它属于最新版本的“scalajs-tools”工件甚至没有的包。

完成我想做的事情的最佳方法是什么?

【问题讨论】:

  • 我不明白你想要达到的目标的一半,但是(长死的)ScalaJSOptimizer 的替代品是StandardLinker,它是Linker 的工厂,它的重要方法是link
  • 您正在寻找的东西被称为(至少在 Scala 研究环境中)“深度嵌入”(或其变体)。这是一个活跃的研究课题,而不是“解决”的问题。对于您的具体问题,我能想到的最好方法是自己编写一个小的 JavaScript 编译器,然后eval 结果。

标签: javascript scala scala.js runtime-compilation


【解决方案1】:

我也不知道你的最终目标是什么,但如果你真的想在运行时编译 Scala.js,最好的办法是查看 scalafiddle.io 的源代码,它就是这样做的,并且首先复制它正在做的任何事情,然后从那里进行更改。

这是处理从 Javascript 编译到 Scala.js 的 IR,然后从 IR 编译到 Javascript String 的代码:

这里有趣的方法是compilelinkfastOptJSfullOptJS)和export。我知道 StackOverflow 不鼓励外部链接,但代码实在太大太粗糙,不值得在这里在线复制。你最好的办法是克隆那个 repo,在你的 IDE 中打开它,看看代码是如何将 Scala.js code: String 转换为 Compiler 类的构造函数的,通过所有中间步骤,从 export 方法返回的最终 Javascript String

【讨论】:

  • 但是那个东西还是只有JVM不是吗?还是它对 scalac 的攻击如此糟糕以至于它可以在 JS 上运行?
  • 是的,它仍然是 JVM。从最初的问题中我不清楚“运行时”是在服务器上还是在客户端上。这仅适用于服务器
【解决方案2】:

您正在尝试做的事情是可能的,并且已经在许多语言中进行了广泛的研究(深度 DSL 嵌入)。要实现您想要的,您必须:

  1. 在 Scala 中查找或构建可以输出 JavaScript 的深度嵌入框架。
  2. 确保框架使用 Scala.js 编译。
  3. 使用此框架构建您的 DSL。

我知道你可以使用的框架是:

  1. DB Lab:我认为它没有 JS 后端,但可以根据您的需要添加。
  2. LMS:有一个 JS 后端,但是,你必须在你的 DSL 中使用 Rep 类型。

您必须与作者核实这些框架是否使用 Scala.js 进行编译,以及它们的 JS 后端的状态如何。

您的提案尝试使用 Scala.js 作为深度嵌入框架,但 Scala.js 无法使用 Scala.js 进行编译。

【讨论】:

  • 谢谢!我实际上已经开始尝试基于 LMS 的 js-scala 库 (github.com/js-scala/js-scala),但是我在使用 Rep[T] 时遇到了麻烦,其中 T 是一个案例类。库本身提供的示例很简单,仅使用原始类型。你还知道哪些更复杂的例子?
  • 让我重新表述我的问题。如何为自己的域类型提供自定义代码生成器?
  • 我想我明白了。
【解决方案3】:

老实说,我认为将其定义为“在运行时将 Scala 表达式编译为 Javascript”是在构建失败的秘诀。 Scala.js 无法编译 Scala,而且可能在不久的将来也无法编译——太多的编译器基础设施是以 JVM 为中心的。

因此,我建议重新定义问题。正式定义您希望能够在运行时使用的语言。 (这很可能是 Scala 的一个子集。)使用 Scala.js 解析器(例如 FastParse)为其编写一个解析器,生成抽象语法树,以及一个将这些语法树转换为 JavaScript 的解释器。

是的,这有点费力。但这是可以实现的,试图在运行时将任意 Scala 编译为 JavaScript,在 Scala.js 中,不是......

【讨论】:

  • 谢谢。但我并不是想将任意 Scala 编译成 Javascript。只是对已经编译成 Javascript 的构建块的布尔运算(见上文)。
  • 我想知道js-scala是否可以用于这个......(github.com/js-scala/js-scala
猜你喜欢
  • 1970-01-01
  • 2015-06-04
  • 2015-02-14
  • 1970-01-01
  • 1970-01-01
  • 2020-05-30
  • 2010-11-01
  • 2019-07-05
  • 1970-01-01
相关资源
最近更新 更多