将JavaScript AST中的注释替换为从注释内容派生的子树

时间:2013-02-06 06:17:08

标签: javascript parsing abstract-syntax-tree

我是doctest的作者,JavaScript和CoffeeScript的快速和脏doctests。我想通过使用JavaScript解析器而不是正则表达式来查找注释来减少库的使用。

我想使用EsprimaAcorn执行以下操作:

  1. 创建AST
  2. 走树,并为每个评论节点:
    1. 从评论节点的文本
    2. 创建一个AST
    3. 使用此子树替换主树中的注释节点
  3. 输入:

    !function() {
    
      // > toUsername("Jesper Nøhr")
      // "jespernhr"
      var toUsername = function(text) {
        return ('' + text).replace(/\W/g, '').toLowerCase()
      }
    
    }()
    

    输出:

    !function() {
    
      doctest.input(function() {
        return toUsername("Jesper Nøhr")
      });
      doctest.output(4, function() {
        return "jespernhr"
      });
      var toUsername = function(text) {
        return ('' + text).replace(/\W/g, '').toLowerCase()
      }
    
    }()
    

    我不知道该怎么做。 Acorn提供了一个walker,它接受​​一个节点类型和一个函数,并在每次遇到指定类型的节点时遍历调用该函数的树。这似乎很有希望,但不适用于评论。

    使用Esprima我可以使用esprima.parse(input, {comment: true, loc: true}).comments来获取评论,但我不确定如何更新树。

2 个答案:

答案 0 :(得分:3)

大多数产生AST的解析器都会丢弃注释。我不知道Esprima或Acorn做了什么,但这可能是个问题。

....事实上,Esprima将评论捕获列为当前错误: http://code.google.com/p/esprima/issues/detail?id=197

...... Acorn的代码就在GitHub中。它似乎也会抛出评论。

所以,看起来你可以先修复任何一个解析器来捕获注释,此时你的任务应该很简单,或者你被卡住了。

我们的DMS软件重组工具包具有在树中捕获注释的JavaScript解析器。它还具有语言 substring 解析器,可用于将注释文本解析为注释所代表的任何类型的JavaScript AST(例如,函数声明,表达式,变量声明......),以及支持机器将这些新的AST移植到主树中。如果你要操作AST,这个子字符串功能可能很重要:大多数解析器不会解析任意语言片段,它们仅用于解析“整个程序”。对于DMS,没有要替换的注释节点;有与ASTs节点相关的注释,因此嫁接过程比“替换注释节点”有点棘手。还很容易。

我会观察到大多数解析器(包括这些)通过使用或应用等效的正则表达式来读取源并将其分解为令牌。因此,如果您已经使用这些来查找注释(这意味着使用它们来定位*非*注释,例如,您需要识别包含类似注释的文本并忽略它们的字符串文字),那么在查找评论方面,做得和解析器一样。如果你想要做的就是用它们的内容完全替换它们,用注释前缀/ suffix / * * / stripped回显源流将完全按照你想要的那样做,所以所有这些解析机制看起来都有点矫枉过正。

答案 1 :(得分:2)

您已经可以使用Esprima来实现您的目标:

  1. 解析代码,获取注释(作为数组)。
  2. 对评论进行迭代,看看每个评论是否符合您的兴趣。
  3. 如果您需要转换评论,请记下其范围。收集所有变换。
  4. 将转换应用于第一个,以便不移动范围。
  5. 这里的诀窍不是改变AST。只需应用文本更改,就像直接在源字符串上执行典型的搜索替换一样。因为替换的位置可能会发生变化,所以您需要收集所有内容,然后从最后一个中进行。有关如何执行此类转换的示例,请查看我的博客文章"From double-quotes to single-quotes"(它处理字符串引号但原则保持不变)。

    最后但同样重要的是,您可能希望使用稍高级别的实用程序,例如Rocambole