AST 入门必知必会

1. AST简介

AST ( Abstract syntax tree )   是编译原理中的一个概念,即源代码语法结构的一种抽象表示。它以树的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。 例如这样的一段 js 代码,可以表示为下面的结构:

function abs(number) {
    if (number >= 0) return number
    else return -number
}

 

AST 入门必知必会

有了 AST,我们面对的就不再是一坨各种符号混杂空格而成的文本字符串,而是一个严谨规范的树形结构。我们可以通过对 AST 树节点的一系列操作,借助机器高效且精准地修改代码。

AST 相关技术在前端中应用场景非常广泛(babel、eslint、代码格式化、自动补全、混淆压缩、Webpack、Typescript、各种跨端框架等等)。大体可以总结为:代码需要按照一定规律进行批量转换时。我们就可以使用 AST。在代码重构中,AST 同样大有可为,可以这么理解,AST 是一个智能机器人,我们要做的就是编写它的行动指令。只要我们能总结出其中的规律,无论代码量有多少,机器人分分钟就能搞定一切,且不会出现任何差错。

2. Babel简介

前端能够实现 AST 转换的类库有很多,这里引入我们可能最熟悉的一个:Babel,下图描述了 Babel 工作的基本流程

AST 入门必知必会

 

其中 parse 与 generate 阶段 babel 都提供了现成的方法,开发者唯一需要关心的是中间的transform (代码转换)过程,核心其实只有两个问题:

  1. 哪些代码是需要修改的?

总结我们需要修改代码的特征,通过 babel.traverse 遍历语法树,配合 visitor 查找到我们需要修改的节点。

  1. 进行怎样的修改?

根据实际需求制定规则,基于节点路径 (path) 进行节点的增删改操作。

下面是一个简单的 demo 演示

const { parse } = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generate = require("@babel/generator").default;

// 源代码
const code = `function square(n) { return n * n; }`;

// parse 解析源代码生成AST
const ast = parse(code, {/*options*/});

// transform 代码转换 
// 遍历AST节点(深度优先)
traverse(ast, { 
    // 通过visitor访问Identifier(标识符)类型的节点
    Identifier(path) {
        // path表示访问到该节点的一条路径,基于path可以进行各种修改操作
         if (path.node.name == 'n') path.node.name = 'x'
    }
})

// generate AST生成目标代码
const output = generate(ast, {/*options*/}, code);

console.log(output.code) // function square(x) { return x * x; }

3. 学习三步走

  1. 熟悉 js 各种节点类型,语法树结构, ASTExplorer 语法树结构速览
  2. 掌握 babel 相关概念及 api babel 插件开发手册
  3. 实战演练,具体问题具体分析 ,过程中可以参考 babel 插件的实现

4. 小结

AST 是一个无比强大的工具,隐去了词法+语法分析的前置过程,帮助我们深入 js 语言底层,得以更加高效精准地对代码动刀。熟练掌握 AST 后,你可能会有下面的感觉

 

AST 入门必知必会

上一篇:AST 入门必知必会


下一篇:Detecting Code Clones with Graph Neural Network and Flow-Augmented Abstract Syntax Tree 笔记(一)