AST抽象语法树
AST是什么
代码中常见的字面量、标识符、表达式、语句、模块语法、class 语法等语句都有各自对应的 AST 节点类型。
AST常见节点类型
1. literal(字面量):本身语义代表一个值
let name = 'iceman'; // iceman ---> StringLiteral 字符串字面量
let age = 30; // 30 ---> NumberLiteral 数字字面量
const isMan = true; // true ---> BooleanLiteral 布林字面量
const reg = /\d/; // /\d/ ---> RegExpLiteral 正则字面量
2. Identifier(标识符):变量名、属性名、参数名等
import { request } form 'framework'; // request ---> Identifier
let name = 'iceman'; // name ---> Identifier
const age = 30; // age ---> Identifier
function talk(name) { // talk, name ---> Identifier
console.log(name); // console, log, name ---> Identifier
}
const obj = { // obj ---> Identifier
name: 'guang' // name ---> Identifier
}
3. Statement(语句):最小代码执行单位
return 'iceman'; // ReturnStatement
if (age > 35) {} // IfStatement
throw new Error('error') // ThrowStatement
try {} catch(e) {} // TryStatement
for (let i = 0; i < 5; i++) {} // ForStatement
4. Declaration(声明):特殊的statement
const listlen = 1; // VariableDeclaration
let listName = 'user'; // VariableDeclaration
function getInfo(info) { // FunctionDeclaration
if(info.isRun){
return info.name;
}
return '';
}
class Car { // ClassDeclaration
constructor() {}
method() {}
}
5. Expression(表达式):与statement的区别在于expression会有返回值
[1,2,3]; // ArrayExpression 数组表达式
age = 1; // AssignmentExpression 赋值表达式
1 + 2; // BinaryExpression二元表达式
var obj = { // ObjectExpression对象表达式
foo: 'foo',
bar: function() {}
}
let getName = function (){} // FunctionExpression函数表达式
const getAge = (age) => { // ArrowFunctionExpression箭头函数表达式
return age;
};
6. Import(导入模块):属于一种特殊的声明语句,有三种类型 ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier
import { environment } from 'framework'; // named import
import { request as req } from 'framework'; // namespaced import
import api from 'framework'; // default import
import * as APP from 'framework'; // namespaced imort
7. Export(导出模块):也属于一种特殊的声明,有三种类型 ExportAllDeclaration | ExportDefaultDeclaration | ExportNamedDeclaration
export * from './iceman'; //all declaration
export default 'iceman'; //default declaration
export const ice = 'iceman'; //named declaration
AST有什么用
代码编译(这里我的理解是各种loader)
- Babel,将ES6 JavaScript转化为ES5 JavaScript
- TypeScript,将TS转化为JS
- Sass,将Sass转化为css
代码加工(这里我的理解是各种plugin)
- Prettier:代码美化
- ESLint:修复语法错误
- uglifyJS:代码压缩,混淆
- @vue/compiler-dom:将vue文件代码拆分成template、script、style代码片段
代码分析
- ESLint:代码语法检查
- Webpack:代码模块打包分析
上面举的例子基本都是基于AST的代码处理工具,有的我用过,有的没用过,但是大致工作流程基本是下面四个阶段:
对于代码编译和加工来说,需要改变源代码,所以需要进行完整个过程,但是代码分析的话,并不涉及修改源代码,所以进行Parsing和Traversing两个步骤就行。
AST如何生成
主要分为两个步骤:
- 词法分析:将整个代码字符串分割成最小语法单元数组。
- 语法分析:在分词基础上建立分析分析语法单元之间的关系。
词法分析
将源代码,生成一系列词法单元(tokens),比如数字,标点,运算符等。
语法分析
将token按照不同的语法结构如声明语句、赋值表达式等转化成有语法含义的抽象语法树结构。
也就是说源代码 --> 词法单元 --> 抽象语法树,分别经过词法分析和语法分析两个过程。
小结
简单认识了一下什么是AST以及一些应用场景,主要是一些学习记录。