轻量级javascript到javascript解析器



我该如何编写一个轻量级的javascript到javascript解析器?一些可以转换代码片段的简单程序

我想基本上使函数中的内部作用域对象是公共的。

所以像这样的

var outer = 42;
window.addEventListener('load', function() {
   var inner = 42;
   function magic() {
       var in_magic = inner + outer;
       console.log(in_magic);
   }
   magic();
}, false);

将编译为

__Scope__.set('outer', 42);
__Scope__.set('console', console);
window.addEventListener('load', constructScopeWrapper(__Scope__, function(__Scope__) {
    __Scope__.set('inner', 42);
    __Scope__.set('magic',constructScopeWrapper(__Scope__, function _magic(__Scope__) {
        __Scope__.set('in_magic', __Scope__.get('inner') + __Scope__.get('outer'));
        __Scope__.get('console').log(__Scope__.get('in_magic'));
    }));
    __Scope__.get('magic')();
}), false);

示范者例子这背后的动机是序列化函数和闭包的状态,并使它们在不同的机器(客户端、服务器、多个服务器)上保持同步。为此,我需要[[Scope]]

的表示形式

问题:

  1. 我可以做这种编译器不写一个完整的JavaScript ->(略有不同)JavaScript编译器?
  2. 我该怎么写这样一个编译器?
  3. 可以重用现有的js -> js编译器吗?

考虑到您想要访问和恢复所有程序状态,我认为您的任务不容易或不短。其中一个问题是,您可能必须在计算过程中的任何时刻捕捉程序状态,对吗?这意味着这个例子并不完全正确;它在执行代码之前捕获状态(除了您已经预先计算了初始化魔术的总和,并且在代码运行原始JavaScript之前不会发生)。我假设您可能希望在执行期间的任何时刻捕获状态。

你所说的问题是,你想要一个JavaScript解析器。我假设您正在想象现有的JavaScript代码J,包括这样一个JavaScript解析器和生成结果代码G所需的任何其他东西,并且当J启动时,它将自己的副本提供给G,制造序列化代码S并以某种方式加载它。(我认为如果G可以处理所有Javascript,那它就太大了)所以你的JavaScript图像包含J,大G, S,并且在它启动时做了一个昂贵的操作(将J提供给G)。

我认为可以更好地为您服务的是一个工具G,它可以离线处理您的原始JavaScript代码J,并生成程序状态/闭包序列化代码S(保存和恢复该状态),可以添加到/替换J以执行。J+S被发送给客户,客户从未看到G或其执行。这将S的生成与J的运行时执行解耦,节省了客户端执行的时间和空间。

在这种情况下,您需要一个工具,使生成这样的代码S最容易。一个纯JavaScript解析器是一个开始,但可能还不够;您将需要符号表支持来知道哪个函数代码与函数调用F(…)相连,以及哪个作用域中的哪个变量定义对应于对变量v的赋值或访问。您可能需要实际修改原始代码J以插入可以捕获程序状态的访问点。你可能需要流分析来找出一些值去了哪里。在JavaScript中坚持所有这些会缩小你的解决方案范围。

对于这些任务,您可能会发现程序转换工具很有用。这些工具包含针对感兴趣的语言的解析器,构建表示程序的ast,支持构造标识符到定义映射("符号表"),可以对表示接入点插入的ast进行修改,或者对表示演示示例的ast进行合成,然后重新生成包含修改后的J和添加的S的有效JavaScript代码。在我所知道的所有程序转换系统中(包括维基百科网站上的所有程序转换系统),没有一个是用JavaScript实现的。

我们的DMS软件再造工具包就是这样一个程序转换系统,提供了我刚才描述的所有功能。(是的,它又大又白;它必须能够处理真正的计算机语言的复杂性)。它有一个JavaScript前端,其中包含到ast的完整JavaScript解析器,以及从修改或合成的ast中重新生成JavaScript代码的机制。(又大又白;还好hoary + hoary仍然只是hoary)。如果有用的话,DMS还提供了对构建控制和数据流分析的支持。

如果你想要一个简单的界面,你可以尝试node-burrito: https://github.com/substack/node-burrito

它使用uglify-js解析器生成AST,然后递归遍历节点。您所要做的就是给出一个测试每个节点的回调函数。您可以更改需要更改的代码,它将输出结果代码。

我会尝试寻找一个现有的解析器来修改。也许你可以改编JSLint/JSHint?

上面的重写有一个问题,您没有将魔术的初始化提升到作用域的顶部。

有很多项目可以解析JavaScript。

  1. Crock的Pratt解析器,它在JavaScript中工作得很好,适合"好的部分",在其他JS中不太好。
  2. es-lab解析器基于ometa,它处理完整的语法,包括克罗克解析器遗漏的许多极端情况。它的性能可能不如克罗克的好。
  3. 水仙解析器和求值器。我在这方面没有太多经验。

还有许多高质量的JavaScript词法分析器,可以让您在令牌级别操作JS。这可能比听起来要困难,因为JavaScript在词法上不是规则的,如果没有完整的解析,预测分号插入是困难的。

我的es5词法分析器是一个为EcmaScript 5精心构建的高效词法分析器,它提供了标记JavaScript的能力。它是启发式的,JavaScript的语法不符合词法规则,但启发式非常好,它提供了一种转换令牌流的方法,这样解释器就可以保证按照词法分析器解释令牌的方式来解释它,所以如果你不相信你的输入,你仍然可以确保安全转换背后的解释是合理的,即使根据一些奇怪的输入的规范不正确。

你的问题似乎与JS Opfuscators和JS Compressors解决的问题属于同一系列——它们以及你需要能够解析并将JS重新格式化为等效脚本;

这里有一个关于混淆器的很好的讨论,你的问题的可能解决方案可能是利用一个自由/开源软件版本的解析和生成器部分。

一个callout,您的示例代码没有考虑到您想要设置/获取的变量的范围,这最终将成为您必须解决的问题。

添加

给定闭包定义函数的作用域问题,您可能不太可能将此问题作为静态解析问题来解决,因为必须导入/导出闭包之外的作用域变量来解析/保存和重新实例化作用域。因此,您可能需要深入研究求值引擎本身,并可能获得V8引擎并对解释器本身进行修改—这是假设您不需要在所有脚本引擎中使用通用的,并且您可以将其绑定到您控制的单个实现。

最新更新