AST介绍

301 阅读7分钟

本文主要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. 表达式

  1. 所有表达式节点都是 Expression 类型的子类型
  2. 表达式是可以被求值的代码片段,它总是会产生一个值。
    1. 表达式可以是简单的,如字面量或变量引用,
    2. 也可以是复杂的,如函数调用或算术运算。
  3. 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. 语句

  1. 所有语句节点都是 Statement 类型的子类型
  2. 语句是执行某种操作的代码单元。语句不一定产生值,但它们会造成某种效果或改变程序状态。
  3. 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. 声明

  1. 所有声明节点都是 Declaration 类型的子类型
  2. 声明用于在程序中引入新的组件,如变量、函数或类。声明通常会创建或修改标识符的绑定。
  3. 例如:
    • let x = 5; (变量声明)
    • function foo() { ... } (函数声明)
    • class MyClass { ... } (类声明)
type Declaration = ClassDeclaration | FunctionDeclaration | VariableDeclaration;

4. 模式

  1. 绑定模式是 BindingPattern 类型的子类型
  2. 模式主要用于解构赋值和函数参数中,用来描述如何从复杂的数据结构中提取值并赋给变量。
  3. 例如:
    • [a, b] = [1, 2] (数组解构)
    • {x, y} = {x: 10, y: 20} (对象解构)
    • function f({name, age}) { ... } (函数参数解构)
type BindingPattern = ArrayPattern | ObjectPattern;

5. 程序

  1. 程序是整个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"
      }
    }
  ]
}

四、参考

docs.esprima.org/en/latest/s…