本文主要AST节点的基础知识,熟悉AST节点是学习和运用AST的基础。
======
一、介绍
AST是代码的中间表示,是经过词法分析、语法分析以后的结果,是代码的中间表示形式。
二、语法树示例
1. 代码
function calculateSum(a, b) {
return a + b;
}
let result = calculateSum(5, 3);
console.log(result);
2. 语法树
Program // 根节点
├── FunctionDeclaration // 函数声明节点
│ ├── id: Identifier(name: "calculateSum") // 函数名称定义
│ ├── params: [ // 参数定义
│ │ Identifier(name: "a"),
│ │ Identifier(name: "b")
│ │ ]
│ └── body: BlockStatement // 函数提及
│ └── ReturnStatement // return
│ └── BinaryExpression // a + b
│ ├── operator: "+"
│ ├── left: Identifier(name: "a")
│ └── right: Identifier(name: "b")
├── VariableDeclaration // 变量声明,可以同时表示多个
│ └── declarations: [
│ VariableDeclarator // 一个变量声明 let
│ ├── id: Identifier(name: "result") // 变量名称 result
│ └── init: CallExpression // 变量初始化,同时也是一个函数调用
│ ├── callee: Identifier(name: "calculateSum")
│ └── arguments: [ // 函数调用入参数
│ NumericLiteral(value: 5),
│ NumericLiteral(value: 3)
│ ]
│ ]
└── ExpressionStatement // 表达式
└── CallExpression // 这个表达式是函数调用
├── callee: MemberExpression // 对象属性访问 console.log
│ ├── object: Identifier(name: "console") // 对象 console
│ └── property: Identifier(name: "log") // 属性 log
└── arguments: [
Identifier(name: "result") // 函数调用的入参数 result
]
三、AST节点的包含关系
Program // 程序
├── Statement // 语句
│ ├── BlockStatement // 块语句
│ │ └── [可包含任何Statement] // 可以包含任何语句
│ ├── ExpressionStatement // 表达式语句
│ │ └── Expression // 表达式
│ ├── IfStatement // 条件语句(如果语句)
│ │ ├── Expression (条件) // 条件表达式
│ │ └── BlockStatement (1-2个) // 块语句(1-2个)
│ ├── ForStatement/WhileStatement // 循环语句(for/while语句)
│ │ ├── Expression (条件) // 条件表达式
│ │ └── BlockStatement // 块语句
│ ├── SwitchStatement // 分支语句(switch语句)
│ │ ├── Expression (条件) // 条件表达式
│ │ └── [多个CaseBlock] // 多个分支块
│ ├── ReturnStatement // 返回语句
│ │ └── [可选 Expression] // 可选的表达式
│ ├── BreakStatement // 中断语句
│ ├── ContinueStatement // 继续语句
│ ├── TryStatement // 异常处理语句(try-catch-finally)
│ │ ├── BlockStatement (try部分) // try块
│ │ ├── [CatchBlock] // 可选的catch块
│ │ └── [FinallyBlock] // 可选的finally块
│ ├── ThrowStatement // 抛出异常语句
│ └── VariableDeclaration // 变量声明
│ ├── Identifier // 标识符
│ └── [可选 Expression (初始化)] // 可选的表达式(初始化)
├── Expression // 表达式
│ ├── Literal // 字面量
│ ├── Identifier // 标识符
│ ├── FunctionExpression/ArrowFunctionExpression // 函数表达式/箭头函数表达式
│ │ ├── [多个 Identifier (参数)] // 参数列表
│ │ └── BlockStatement // 函数体块语句
│ ├── ObjectExpression // 对象表达式
│ │ └── [多个 Expression (属性)] // 多个表达式(属性)
│ ├── ArrayExpression // 数组表达式
│ │ └── [多个 Expression] // 多个表达式
│ ├── BinaryExpression/UnaryExpression // 二元/一元表达式
│ │ └── Expression (1-2个) // 1-2个表达式
│ ├── ConditionalExpression // 条件表达式(三元表达式)
│ │ └── [3个 Expression] // 3个表达式
│ ├── CallExpression // 函数调用表达式
│ │ ├── Expression (函数) // 表达式(函数)
│ │ └── [多个 Expression (参数)] // 多个表达式(参数)
│ ├── MemberExpression // 成员表达式
│ │ ├── Expression (对象) // 表达式(对象)
│ │ └── Expression (属性) // 表达式(属性)
│ └── NewExpression // 新建实例表达式
│ ├── Expression (构造函数) // 构造函数表达式
│ └── [多个 Expression (参数)] // 多个表达式(参数)
├── Declaration // 声明
│ ├── VariableDeclaration // 变量声明
│ ├── FunctionDeclaration // 函数声明
│ │ ├── Identifier (函数名) // 标识符(函数名)
│ │ ├── [多个 Identifier (参数)] // 参数列表
│ │ ├── BlockStatement (函数体) // 函数体块语句
│ │ └── {generator: true} // 生成器标识符
│ └── ClassDeclaration // 类声明
│ ├── Identifier (类名) // 标识符(类名)
│ └── ClassBody (类体) // 类体
├── ImportDeclaration // 导入声明
│ ├── [多个 ImportSpecifier] // 多个导入说明符
│ ├── ImportDefaultSpecifier // 默认导入说明符
│ └── ImportNamespaceSpecifier // 命名空间导入说明符
└── ExportDeclaration // 导出声明
├── ExportNamedDeclaration // 命名导出声明
├── ExportDefaultDeclaration // 默认导出声明
└── ExportAllDeclaration // 导出所有声明
三、节点数据结构和继承关系
数据类型以Esprima-Appendix A. Syntax Tree Format为参考
Node
├── Program -
├── Statement
│ ├── BlockStatement -
│ ├── BreakStatement
│ ├── ContinueStatement
│ ├── DebuggerStatement
│ ├── EmptyStatement -
│ ├── ExpressionStatement
│ ├── IfStatement
│ ├── ForStatement
│ ├── ForInStatement
│ ├── ForOfStatement
│ ├── WhileStatement
│ ├── DoWhileStatement
│ ├── SwitchStatement
│ ├── LabeledStatement
│ ├── ReturnStatement -
│ ├── ThrowStatement
│ ├── TryStatement
│ └── WithStatement
├── Declaration
│ ├── FunctionDeclaration -
│ ├── VariableDeclaration -
│ └── ClassDeclaration
├── Expression
│ ├── ThisExpression -
│ ├── ArrayExpression
│ ├── ObjectExpression
│ ├── FunctionExpression
│ ├── ArrowFunctionExpression
│ ├── ClassExpression
│ ├── TaggedTemplateExpression
│ ├── MemberExpression -
│ ├── Super
│ ├── MetaProperty
│ ├── NewExpression
│ ├── CallExpression -
│ ├── UpdateExpression
│ ├── AwaitExpression
│ ├── UnaryExpression
│ ├── BinaryExpression -
│ ├── LogicalExpression
│ ├── ConditionalExpression
│ ├── YieldExpression
│ ├── AssignmentExpression
│ └── SequenceExpression
└── Pattern
├── ArrayPattern
└── ObjectPattern
// 特殊关系
Identifier (可作为 Expression 或 Pattern) -
Literal (作为 Expression 的一种) -
FunctionDeclaration (同时是 Declaration 和 Statement) -
VariableDeclaration (同时是 Declaration 和 Statement)
四、重要节点介绍
1. 表达式
- 所有表达式节点都是 Expression 类型的子类型
- 表达式是可以被求值的代码片段,它总是会产生一个值。
- 表达式可以是简单的,如字面量或变量引用,
- 也可以是复杂的,如函数调用或算术运算。
- demo:
5(字面量)x(变量引用)a + b(算术表达式)foo()(函数调用)new Date()(对象创建)
type Expression = ThisExpression | Identifier | Literal |
ArrayExpression | ObjectExpression | FunctionExpression |
ArrowFunctionExpression | ClassExpression |
TaggedTemplateExpression | MemberExpression | Super | MetaProperty |
NewExpression | CallExpression | UpdateExpression | AwaitExpression |
UnaryExpression | BinaryExpression | LogicalExpression |
ConditionalExpression | YieldExpression | AssignmentExpression |
SequenceExpression;
2. 语句
- 所有语句节点都是 Statement 类型的子类型
- 语句是执行某种操作的代码单元。语句不一定产生值,但它们会造成某种效果或改变程序状态。
- DEMO:
if (condition) { ... }(条件语句)for (let i = 0; i < 10; i++) { ... }(循环语句)return value;(返回语句)throw new Error();(异常抛出语句)
type Statement = BlockStatement | BreakStatement | ContinueStatement |
DebuggerStatement | DoWhileStatement | EmptyStatement |
ExpressionStatement | ForStatement | ForInStatement |
ForOfStatement | FunctionDeclaration | IfStatement |
LabeledStatement | ReturnStatement | SwitchStatement |
ThrowStatement | TryStatement | VariableDeclaration |
WhileStatement | WithStatement;
3. 声明
- 所有声明节点都是 Declaration 类型的子类型
- 声明用于在程序中引入新的组件,如变量、函数或类。声明通常会创建或修改标识符的绑定。
- 例如:
let x = 5;(变量声明)function foo() { ... }(函数声明)class MyClass { ... }(类声明)
type Declaration = ClassDeclaration | FunctionDeclaration | VariableDeclaration;
4. 模式
- 绑定模式是 BindingPattern 类型的子类型
- 模式主要用于解构赋值和函数参数中,用来描述如何从复杂的数据结构中提取值并赋给变量。
- 例如:
[a, b] = [1, 2](数组解构){x, y} = {x: 10, y: 20}(对象解构)function f({name, age}) { ... }(函数参数解构)
type BindingPattern = ArrayPattern | ObjectPattern;
5. 程序
- 程序是整个JavaScript代码的顶层结构。它可以包含一系列语句、声明和模块项(如导入和导出)。在AST中,Program通常是根节点,代表整个源代码文件。
type StatementListItem = Declaration | Statement;
type ModuleItem = ImportDeclaration | ExportDeclaration | StatementListItem;
五、DEMO
1. MemberExpression/ThisExpression/Identifier
# code
this.name.firstName
# AST表示
MemberExpression // this.name.firstName
├── object: MemberExpression // this.name
│ ├── object: ThisExpression // this
│ └── property: Identifier // .
│ └── name: "name" // name
└── property: Identifier // .
└── name: "firstName" // firstName
# 数据结构
{
type: "MemberExpression", // this.name.firstName
object: {
type: "MemberExpression", // this.name
object: {
type: "ThisExpression" // this
},
property: { // name
type: "Identifier",
name: "name"
}
},
property: { // .firstName
type: "Identifier",
name: "firstName"
}
}
2. Program、FunctionDeclaration、Identifier、BlockStatement、ReturnStatement、BinaryExpression、VariableDeclaration、VariableDeclarator、CallExpression、Literal、ExpressionStatement、MemberExpression
# CODE
function calculateSum(a, b) {
return a + b;
}
let result = calculateSum(5, 3);
console.log(result);
# AST
Program // 根节点
├── FunctionDeclaration // 函数声明节点
│ ├── id: Identifier(name: "calculateSum") // 函数名称定义
│ ├── params: [ // 参数定义
│ │ Identifier(name: "a"),
│ │ Identifier(name: "b")
│ │ ]
│ └── body: BlockStatement // 函数提及
│ └── ReturnStatement // return
│ └── BinaryExpression // a + b
│ ├── operator: "+"
│ ├── left: Identifier(name: "a")
│ └── right: Identifier(name: "b")
├── VariableDeclaration // 变量声明,可以同时表示多个
│ └── declarations: [
│ VariableDeclarator // 一个变量声明 let
│ ├── id: Identifier(name: "result") // 变量名称 result
│ └── init: CallExpression // 变量初始化,同时也是一个函数调用
│ ├── callee: Identifier(name: "calculateSum")
│ └── arguments: [ // 函数调用入参数
│ NumericLiteral(value: 5),
│ NumericLiteral(value: 3)
│ ]
│ ]
└── ExpressionStatement // 表达式
└── CallExpression // 这个表达式是函数调用
├── callee: MemberExpression // 对象属性访问 console.log
│ ├── object: Identifier(name: "console") // 对象 console
│ └── property: Identifier(name: "log") // 属性 log
└── arguments: [
Identifier(name: "result") // 函数调用的入参数 result
]
# 数据结构
{
type: "Program",
sourceType: 'script',
body: [
{
type: "FunctionDeclaration",
id: { type: "Identifier", name: "calculateSum" },
params: [
{ type: "Identifier", name: "a" },
{ type: "Identifier", name: "b" }
],
body: {
type: 'BlockStatement',
body: [
{
type: 'ReturnStatement',
argument: {
type: 'BinaryExpression',
operator: '+',
left: { type: "Identifier", name: "a" },
right: { type: "Identifier", name: "b" }
}
}
]
},
generator: false,
async: false,
expression: false
},
{
type: 'VariableDeclaration',
declarations: [
{
type: 'VariableDeclarator',
id: { type: "Identifier", name: "result" },
init: {
type: 'CallExpression',
callee: { type: "Identifier", name: "calculateSum" },
arguments: [
{ type: 'Literal', value: 5, raw: '5' },
{ type: 'Literal', value: 3, raw: '3' }
]
}
}
],
kind: 'let'
},
{
type: 'ExpressionStatement',
expression: {
type: 'CallExpression',
callee: {
type: "MemberExpression",
object: { type: "Identifier", name: "console" },
property: { type: "Identifier", name: "log" },
computed: false
},
arguments: [
{ type: 'Identifier', name: "result" }
]
}
}
]
}
3. Import
## CODE
// 导出
export const PI = 3.14159;
export function square(x) {
return x * x;
}
export default class Circle {
constructor(radius) {
this.radius = radius;
}
}
// 导入
import Circle, { PI, square } from './math';
import * as mathUtils from './math';
## AST
Program
├── ExportNamedDeclaration
│ └── VariableDeclaration
│ └── VariableDeclarator
│ ├── id: Identifier(name: "PI")
│ └── init: Literal(value: 3.14159)
│
├── ExportNamedDeclaration
│ └── FunctionDeclaration
│ ├── id: Identifier(name: "square")
│ └── params: [Identifier(name: "x")]
│
├── ExportDefaultDeclaration
│ └── ClassDeclaration
│ ├── id: Identifier(name: "Circle")
│ └── body: ClassBody
│
├── ImportDeclaration
│ ├── specifiers: [
│ │ ImportDefaultSpecifier(local: Identifier(name: "Circle")),
│ │ ImportSpecifier(imported: Identifier(name: "PI"), local: Identifier(name: "PI")),
│ │ ImportSpecifier(imported: Identifier(name: "square"), local: Identifier(name: "square"))
│ │ ]
│ └── source: Literal(value: "./math")
│
└── ImportDeclaration
├── specifiers: [
│ ImportNamespaceSpecifier(local: Identifier(name: "mathUtils"))
│ ]
└── source: Literal(value: "./math")
## AST JSON
{
"type": "Program",
"body": [
{
"type": "ExportNamedDeclaration",
"declaration": {
"type": "VariableDeclaration",
"declarations": [
{
"type": "VariableDeclarator",
"id": {
"type": "Identifier",
"name": "PI"
},
"init": {
"type": "Literal",
"value": 3.14159
}
}
],
"kind": "const"
}
},
{
"type": "ExportNamedDeclaration",
"declaration": {
"type": "FunctionDeclaration",
"id": {
"type": "Identifier",
"name": "square"
},
"params": [
{
"type": "Identifier",
"name": "x"
}
],
"body": {
"type": "BlockStatement",
"body": [
{
"type": "ReturnStatement",
"argument": {
"type": "BinaryExpression",
"operator": "*",
"left": {
"type": "Identifier",
"name": "x"
},
"right": {
"type": "Identifier",
"name": "x"
}
}
}
]
}
}
},
{
"type": "ExportDefaultDeclaration",
"declaration": {
"type": "ClassDeclaration",
"id": {
"type": "Identifier",
"name": "Circle"
},
"body": {
"type": "ClassBody",
"body": [
{
"type": "MethodDefinition",
"key": {
"type": "Identifier",
"name": "constructor"
},
"value": {
"type": "FunctionExpression",
"params": [
{
"type": "Identifier",
"name": "radius"
}
],
"body": {
"type": "BlockStatement",
"body": [
{
"type": "ExpressionStatement",
"expression": {
"type": "AssignmentExpression",
"operator": "=",
"left": {
"type": "MemberExpression",
"object": {
"type": "ThisExpression"
},
"property": {
"type": "Identifier",
"name": "radius"
}
},
"right": {
"type": "Identifier",
"name": "radius"
}
}
}
]
}
}
}
]
}
}
},
{
"type": "ImportDeclaration",
"specifiers": [
{
"type": "ImportDefaultSpecifier",
"local": {
"type": "Identifier",
"name": "Circle"
}
},
{
"type": "ImportSpecifier",
"imported": {
"type": "Identifier",
"name": "PI"
},
"local": {
"type": "Identifier",
"name": "PI"
}
},
{
"type": "ImportSpecifier",
"imported": {
"type": "Identifier",
"name": "square"
},
"local": {
"type": "Identifier",
"name": "square"
}
}
],
"source": {
"type": "Literal",
"value": "./math"
}
},
{
"type": "ImportDeclaration",
"specifiers": [
{
"type": "ImportNamespaceSpecifier",
"local": {
"type": "Identifier",
"name": "mathUtils"
}
}
],
"source": {
"type": "Literal",
"value": "./math"
}
}
]
}