backend/js 设计

设计目标

规范描述了第二条实现路径:编译为 JavaScript 的 MoonBit 代码把类型化数组缓冲区传给 Node.js 插件,插件调用与原生后端相同的 C 运行时。backend/js 为这条路径预留了包并固定其身份,使模块的其余部分已经可以在策略、能力表和提交中指定 JavaScript 目标。

数学背景

这个包不做任何计算。它参与的唯一结构是后端的和类型

B={ Native,JavaScript },B = \{\, \mathrm{Native}, \mathrm{JavaScript} \,\},

每个后端包都提供一个指称自身的常量 backend_target∈B\texttt{backend\_target} \in B。对 JavaScript 包而言,该常量是 JavaScript\mathrm{JavaScript},而 shared 设计页面描述的 v1 策略子集 P1P_1 排除了它,因此任何指定该后端的策略或提交在到达运行时之前就会被拒绝。

设计决策

先有包,后有后端

现在就声明这个包,可以保持规范中的模块布局(backend/native 与 backend/js 并列),并让代码依赖 @js.backend_target() 而不是 shared 的某个构造器。后端实现之后,其外部声明和包装会放在这里,无需新的导入路径。

暂无外部声明

js/ 中的插件只导出 runtimeName,也没有链接 C 运行时,因此没有可声明的东西。声明没有实现的函数能够编译,却会在运行时失败,这比不提供它们更糟。

正确性 / 不变量

  • backend_target() 返回 JavaScript,default_plan_kind() 返回 Map,package_name() 返回 "backend/js";这个包没有状态。
  • 这个包可以在所有目标上构建,包括 js。

被否决的方案

  • 在后端存在之前省略这个包。 那样下游代码就没有一个稳定的地方来引用 JavaScript 后端。
  • 在 JavaScript 目标上用 MoonBit 运行内核的桩实现。 它会绕过 C 运行时和规范中的所有权规则,得到真正的后端未必能复现的结果。

边界

这个包不执行计划或工作流,不声明外部函数,不加载 Node.js 插件,也不在 JavaScript 边界上传递数据。