AST(Abstract Syntax Tree) 抽象语法树
为什么要谈 AST?
如果你查看目前任何主流的项目中的devDependencies,会发现前些年的不计其数的插件诞生。比如,babel、css 预处理器、eslint、prettier 等。有很多 js 模块我们不会在生产环境用到,但是它们在我们的开发过程中充当着重要的角色。所有的上述工具都是建立在 AST 之上。
什么是 AST?
It is a hierarchical program representation that presents source code structure according to the grammar of a programming language, each AST node corresponds to an item of a source code.
它是根据编程语言的语法来展示源码结构的分层程序表示,每个 AST 节点都对应着源码中的一部分(item 不知道怎么翻译比较好,暂时翻译为部分)。
让我们看个例子:

其中的重点是,从一段代码,我们可以得到一个树形结构的数据。代码中的每一部分都和树中的节点匹配。
如何从一段代码得到 AST?

幸运的是,我们并不需要过一遍从高级语言代码到二进制的所有步骤。我们只对词法分析(Lexical Analysis)和语法分析(Syntax Analysis)感兴趣,而这两步也是从代码生成 AST 过程中最重要的部分。
词法分析(Lexical Analysis)
第一步,词法分析。
词法分析器(或者叫扫描器——scanner)会读取代码,然后使用定义好的规则生成 token。同时,它也会移除空白字符,注释等。最后,整个代码会被分离成一系列的 token。

我们可以看到一个 token 就是一个对象,内部有值和类型的信息。
词法分析器会一个字符一个字符扫描代码,然后当它遇到了空白字符、操作符以及特殊字符等时,它会判断这个词已经结束了。
语法分析(Syntax Analysis)
第二步,语法分析。
语法分析器(或者叫解析器——parser)会接受词法分析生成的一系列 token,然后会将它们转化为树形结构,最后会验证语言语法,如果有语法错误的话,会抛出语法错误。

当生成一棵树时,一些解析器会省略不必要的 token(比如重复的括号)。所以生成的抽象语法树可能并不是 100%匹配代码的,不过了解这个机制存在就好,不用太过深究。另一方面,也存在「具体语法树(Concrete Syntax Tree)」,它是 100%匹配代码的。
AST playground
然后介绍一个可以在线生成 AST 的网站——astexplorer,它同时也支持了很多除了 JS 之外的语言。
Babel
Babel 是一个 JS 解析器(compiler)。
Babel 是一个主要用来将 ECMAScript 2015+ 代码转换为向后兼容当前和更老版本浏览器或者环境代码的工具链。
主要功能
- 转换语法。
- polyfill 目标环境缺失的功能。
- 源码转换(codemods)。
- 还有更多其他功能(可以去官网查看哦~)
可插拔(Pluggable)
**Babel 是由插件组成的(Babel is built out of Pluggins)。**使用现有的或者自己写的插件可以组成自己的语法转换流水线。
你可以利用上面说到的astexplorer.net随时随地的创建插件,或者使用generator-babel-plugin来生成插件模版。
简单插件的例子:
// A plugin is just a function
// 一个插件就是一个函数
export default function ({ types: t }) {
return {
visitor: {
Identifier(path) {
let name = path.node.name; // 反转每个节点的名称: JavaScript -> tpircSavaJ
path.node.name = name.split("").reverse().join("");
},
},
};
}
左上:转换之前的代码 右上:生成的语法树 左下:自定义的反转名称的插件 右下:转换的结果
可调试(Debuggable)
支持 Source map,它可以让你很方便的调试编译后的代码。
Source map 是一种将编译后的代码映射回为未构建状态的代码的方式。