再说两句 Abstract Syntax Tree

上一篇文章里面提到用AST来做一些代码的小改动,很多读者说是在用“大炮打蚊子”。这个pshu也承认,有些情况确实用sed这个命令行工具就能又快又好的解决,但其实稍微复杂一点的情况话就很难胜任了,比如多个括号的嵌套就很难解决了,这类问题交给 AST 就非常的轻松。

在 npm 上看看依赖于 @babel/parser 的库,大家就会发现AST 这个东西几乎涵盖了代码的方方面面。以一个 JavaScript 的开发者举例,只要你在写代码 AST 就一直跟随着你。当编写代码的时候的 lint 工具对你的代码的静态检查、IDE 的代码自动补全都离不开 AST 在背后默默的付出。写完代码,ES6转ES5、代码打包的时候,依然需要 AST。作为一个开发者去了解 AST并且学习如何使用 AST 无疑是提高个人水平的重要途径;学会了 AST 就会多了一项用代码写代码的神力。想想都很兴奋啊。

那这篇文章和大家分享下 pshu 在使用 AST的一些经验。

## 经验一: 最好使用 Typescript

这里就不泛泛的吹 Typescript,就具体的说下 Typescript 的类型系统对我们在操作 AST 阶段上的帮助。

第一个帮助就是对节点属性的自动补全的帮助。因为 AST 的节点类型数量众多,即使你的记忆力再强大也很难记住所有的节点属性和它正确的拼写。还有一些看起来很接近的节点,属性的名字差别却很大。像下面的 for of 节点和 for 语句节点看起来很近但是属性相差很大,有了 ts 的 types 系统这些问题都不是问题,配合 IDE 的补全简直如有神助。

第二个帮助也是在类型方面的, 不过是另外的一个角度。在处理 AST 的时,有些节点的类型是不确定的,它的属性类型有多种可能。比如上面的 ForStatement 这个节点 init 属性的类型的就有三种可能 (VariableDeclaration | Expression | null)。如果你不了解你要操作的节点的属性的多种可能,直接把 init 当 VariableDeclaration 去使用,Typescript 就会提醒某个 VariableDeclaration 的属性不存在在Expression中。这样就能避免很多在运行时才会发现的问题。

pshu 第一次操作 AST 的时候直接用 JavaScript 写的,加上经验不足,自以为写了一个好用的脚本,执行的时候就发现有各种  `Cannot read property ‘xxx' of undefined `的错误。用了 Typescript 就自信多了。

关于这部分最后还有一点就是多使用 @babel/types 中提供的 guard 函数 isXXXX(node: object | null | undefined, opts?: object | null) ;和 NodePath 对象的isXXX 成员函数。这些函数可以帮我们在编码阶段和运行态确定需要操作节点的类型。而且函数的第二个参数 opts 还能帮我们完成一些简单的匹配。

比如二元表达式的定义如下,


想判断 AST 节点 node 是不是加法的二元表达式的话可能会写 if 条件判断。


但是如果用上 opts 参数的话代码就会简洁一些。


## 经验二: 组合操作

这个什么意思呢? 我们在做 AST 变换操作的时候可能会有多个操作。每个操作的对象会是不同是节点类型。如果每一个操作遍历一次 AST 的话,在 AST 非常大的时候回非常的耗时。而且通常情况下 AST 确实会非常的巨大,这个大家可那一个稍微大点的 JavaScript 文件试试看就知道了。

那 pshu 这里是怎么做的呢?首先先定义一个AST操作的函数的类型。那根据自己的需要会写很多的 Transformer 函数。


然后实现一个工具函数和工具类用来组合和执行这些Transformer函数。工具函数只是简单的对节点依次执行需要组合的 transforms。


而执行的工具类也只是配置好 traverse 的 enter 事件的处理,然后就开始遍历 AST 即可。


这样做的好处就在于分离了不同的AST操作的定义和执行。假设你定义了10个 Transformer,那在对AST变换的时候可以根据配置, 组合几个需要的Transformer 来执行 (runWithAst) 。现实的一个例子就是可以根据程序是否接受 - - verbose选项决定 是否要组合进 logger transformer。

以上代码的例子放在了这里:https://gitee.com/stormslowly/ast_and_ts [点击原文地址直达]

以上就是 pshu 在 AST 方面的两点经验,希望对大家有帮助,也希望大家多多转发点赞! 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值