了解抽象语法树

149 阅读5分钟

抽象语法树(AST)

AST语法树将源代码分解为节点,每个节点代表一个语法元素,如函数,变量,运算符等。树的结构反映了代码的层次关系,根节点通常表示整个代码结构。子节点则表示更细致的部分 源代码转换为AST树: astexplorer.net/

源码字符串是如何转化为ast树结构的

  1. 经过词法分析(Lexical Analysis)
    • 目标:将源码字符串分割成有意义的词法单元(token)
    • 过程:词法分析器逐个字符读取源码,识别关键字、变量名、运算符、括号等。
    • 结果:生成一系列词法单元,例如
[
  { type: 'keyword', value: 'function' },
  { type: 'identifier', value: 'add' },
  { type: 'punctuator', value: '(' },
  { type: 'identifier', value: 'a' },
  { type: 'punctuator', value: ',' },
  { type: 'identifier', value: 'b' },
  { type: 'punctuator', value: ')' },
  { type: 'punctuator', value: '{' },
  { type: 'keyword', value: 'return' },
  { type: 'identifier', value: 'a' },
  { type: 'punctuator', value: '+' },
  { type: 'identifier', value: 'b' },
  { type: 'punctuator', value: ';' },
  { type: 'punctuator', value: '}' }
]

  1. 经过语法分析(Syntax Analysis)
    • 目标:根据编程语言的语法规则,将词法单元组合成更复杂的语法结构。
    • 过程:语法分析器通过算法(如递归下降法),解析词法单元,识别语句、表达式、函数等结构。
    • 结果:生成语法树(Parse Tree),反映代码的层次结构。
  2. 抽象语法树(AST)构建
    • 目标:将语法树转换为更抽象的表示,忽略与语义无关的细节
    • 过程:根据语法规则,将语法树中的节点映射到AST节点,每一个节点代表一个语法元素。
    • 结果:生成AST树
{
  type: 'FunctionDeclaration',
  id: {
    type: 'Identifier',
    name: 'add'
  },
  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'
          }
        }
      }
    ]
  }
}

  1. 错误处理
    • 目标:检测源代码是否符合语法规则
    • 过程:在词法分析和语法分析的过程中,检测词法单元和语法结构是否符合语法规则
    • 结果:如果有错误则生成错误报告,否则继续生成AST树

日常开发中,哪些场景会用到AST?

1. 代码分析工具

  • 静态代码检查工具:如 ESLintSonarQubeCodeClimate 等。这些工具通过解析代码生成 AST,然后检查代码中的潜在问题,例如未使用的变量、潜在的错误或不符合编码规范的地方。
  • 代码质量工具:如 JSHintJSLint 等,通过分析 AST 来检测代码质量问题。

2. 代码转换工具

  • 代码重构工具:如 BabelTypeScript 等。这些工具使用 AST 来转换代码,例如将 ES6 代码转换为兼容性更好的 ES5 代码,或者将 TypeScript 转换为 JavaScript。
  • 代码格式化工具:如 PrettierESLint(配合格式化插件)。这些工具通过解析 AST 来重新格式化代码,确保代码风格一致。

3. 编译器和解释器

  • 编译器(如 GCCClang)和解释器(如 Node.js)在处理代码时会生成 AST。AST 是编译过程中的关键中间表示,用于代码优化和生成目标代码。

4. 调试工具

  • 调试器:如 Chrome DevToolsVisual Studio Debugger 等。调试器通过解析代码生成 AST 来理解代码结构,从而支持断点设置、变量查看等功能。

5. 静态类型检查

  • TypeScriptFlow 等静态类型检查工具通过解析代码生成 AST,然后进行类型推断和检查,确保代码的类型安全。

6. 代码生成

  • 模板引擎:如 EJSHandlebars 等。这些工具通过解析模板生成 AST,然后根据数据生成最终的 HTML 或其他格式的输出。
  • 代码生成工具:如 GraphQL Code Generator,通过解析 AST 生成对应的代码文件。

7. IDE 和代码编辑器

  • 智能感知:IDE(如 VS CodeIntelliJ IDEA)通过解析代码生成 AST,从而提供智能感知( IntelliSense)、代码补全、语法高亮等功能。
  • 代码导航:IDE 使用 AST 来支持跳转到定义、查找引用等功能。

8. 测试工具

  • 单元测试框架:如 JestMocha 等。虽然这些工具本身不直接使用 AST,但它们可以通过解析代码生成 AST 来分析代码覆盖率、测试用例覆盖率等。
  • 覆盖率工具:如 Istanbul,通过解析代码生成 AST 来计算代码覆盖率。

9. 代码混淆和优化

  • 代码混淆工具:如 UglifyJSWebpack 等,通过解析 AST 来混淆代码,使其难以被逆向工程。
  • 代码优化工具:如 Babel 的优化插件,通过解析 AST 来优化代码性能。

10. 代码审查工具

  • 审查工具:如 GitHub Code ReviewCodacy 等,通过解析代码生成 AST 来提供代码审查建议,例如代码风格、潜在 bug 等。

11. 文档生成工具

  • API 文档生成工具:如 JSDocTypeDoc 等,通过解析代码生成 AST 来提取代码注释和结构,生成 API 文档。

12. 代码依赖分析

  • 依赖分析工具:如 WebpackRollup 等,通过解析代码生成 AST 来分析代码依赖关系,从而进行模块打包和优化。

13. 代码迁移工具

  • 迁移工具:如 babel-upgradecodemod 等,通过解析代码生成 AST 来自动迁移代码,例如将旧版本的代码迁移到新版本的语法或库。

14. 代码覆盖率工具

  • 代码覆盖率工具:如 istanbul,通过解析代码生成 AST 来分析代码覆盖率,帮助开发者了解哪些代码被测试覆盖,哪些没有。

15. 代码格式化工具

  • 格式化工具:如 prettier,通过解析代码生成 AST 来重新格式化代码,确保代码风格一致。

手写loader通过AST操作源码