ast语法树初探

news/2024/7/23 19:27:25 标签: javascript, webpack, 前端

前端开发中,使用了很多工具,譬如webpack、eslint来提升研发效率,但我们并不知道这些工具的实现原理。基于这些工具的核心都是抽象语法树,那我们就从抽象语法树开始理解底层原理的新世界吧。

一、抽象语法树是什么

顾名思义,首先可以确定的是,这是一颗跟语法相关的树。

先上一盘硬菜,维基百科定义如下:

In computer science, an abstract syntax tree (AST), or just syntax tree, is a tree representation of the abstract syntactic structure of source code written in a programming language.

也就是说,抽象语法树,是通过编程语言编写的代码的抽象语法结构。

用通俗的话讲,我们所使用的编程语言是一门对人类友好的语言,但是对于程序分析来讲,并不友好。因此,需要将编程语言转译成对程序分析友好的语言。

太干了,来点配菜。

我们结合编译过程,来说明抽象语法树的作用。

如下图所示,一般的编译过程分为六个过程。

 那么在语法分析阶段,就是要将词法分析阶段得到的分词结果整合成一棵语法树。简单举个例子:

代码:

1

2

3

4

function foo(a) {

    let b = a + 3;

    return b;

}

将这个函数转成抽象语法树,其核心部分如下图所示:

blockstatement 块级作用域。

VariableDecalaration 变量声明

VariableDecalarator 变量声明器

Returnstatement 返回语句

 在转成语法树之后,就可以对语句进行语法检查或进行修改了。

二、 语法树的应用

前面提到,可以通过对语法树分析来进行语法检查,有没有很熟悉? 有没有想到我们日常写代码过程中用到的eslint 插件、括号高亮插件等。 没有错,他们就是通过对ast 抽象语法树进行分析,来达成语法检查和高亮目的。

话不多说,看图。

 这是一个ast 在我们开发流程中的一个应用总结。

编写代码:我们用 vue的 模板语法去定义一些功能,而这些模板语法最后都要通过对 ast 进行分析最终转为原生 html 和原生 js。

babel 、webpack 和 ast 的关系:

开发过程中,我们使用了大量处于提案阶段的 es6 的 语法,譬如装饰器、箭头函数、模板字符串等,而这些语法,实际上浏览器本身并不支持。因此,需要将其转成 浏览器支持的 es5 代码。这个es 降级的过程就是通过 babel 完成的,而 babel 的核心也就是通过对 ast 进行更改,从而实现 es 语法降级。

webpack 作为模块化开发的主力军,在打包阶段,也是通过对语法树进行分析,最终打包成一个文件上传到服务器上去的。

浏览器执行代码和 ast 的关系:

如图中所示,浏览器执行js 代码的过程和我们上面所阐述的编译的六个阶段是极其一致的。

综上所述,语法树和我们开发的整个过程都是息息相关的。

认识到了语法树在开发过程中的重要性。 接下来,我们通过 babel 的核心库 来简单模拟 es6 转 es5 的过程。

转译过程大致可以分为三步:

  1. 生成语法树
  2. 语法树遍历,更改
  3. 再次遍历语法树,生成新的代码。

通过库 esprima 生成语法树, 通过库 estraverse 遍历语法树并进行语法更改, 通过库 escodegen 遍历语法树,并生成新的代码。 

三、 语法树的生成

语法树生成使用的库是 esprima。

我们先通过一个简单的es6 例子来说明。

es6 通过 let 关键字进行变量声明,从而实现块级作用域。那么转成 es 5 的话只能是 ‘var’。即,代码 ”let a = 15; “ 转变为 ”var a = 15;“。

首先,导入所使用的几个库(库的地址在本文末尾。)并定义字符串。

1

2

3

4

const prima = require('esprima');

const codegen = require('escodegen');

const traverse = require('estraverse');

var  code2 = 'let a = 2';

我们知道,如果要转成语法树,首先要进行词法分析,通过调用esprima 下的 tokenize函数(console.log(prima.tokenize(code2)))可以查看其生成的token。也可以通过可视化工具esprima 可视化查看词法分析结果。

从图中可以看出,esprima 对字符串中的每一个此进行解析,并赋予相应的 type。

在词法解析结束后,再进行语法解析形成 ast 树,可以通过命令行

1

console.log(prima.parseScript(code2));

查看其 ast 的结果,也可以通过 ast 可视化工具 查看其结果。这里展示通过 ast 可视化工具的结果:

 

es6 语法树:     

es5语法树:

 对比这两棵语法树,我们可以看出,其唯一的区别在于,变量声明下,其 kind 节点的值。 那么,接下来,在遍历语法树的时候,我们只要对 node 下的 kind 节点进行变更就可以完成语法转变了。

四、语法树的遍历和更改

我们可以通过  estraverse下的 traverse 函数进行语法树遍历并进行相应更改。

1

2

3

4

5

6

7

8

9

const ast2 = prima.parseScript(code2);

traverse.traverse(ast2, {

    enter(node) {

        if(node.kind === 'let') {

            node.kind = 'var';

        }

    },

});

五、生成 es5 代码

我们通过 escodegen 下的 generate 函数生成 新的es5 代码:

1

2

3

let code2_es5 = codegen.generate(ast2);

console.log(code2_es5);

//'var a = 2;'

写到这里,基本上对 ast 的 what、why、how 进行了一个基本的介绍。 但美中不足的是,上面对于语法树的解析只是利用库函数进行的。接下来,给大家介绍一些 ast 相关的小知识,并尝试带大家,读一读这些函数的源代码。

六、AST 小知识

js 解析器有哪些?我们所使用的工具内核是什么?

常用的 js 解析器有:

esprima: https://github.com/jquery/esprima

acorn:https://github.com/acornjs/acorn

acorn 的诞生晚于 esprima,期因是 esprima 转换速度太慢。

而 babel 目前所用的解析器 fork 自 acorn。webpack 的核心 parser 也是 acorn。而 eslint 作为一个可配置的代码规范检查工具,可以任意选择定义解析器来使用。

而不管是那个解析器,他们解析得到的 ast 树都符合ast 规则:https://github.com/estree/estree

规则起源:

在v8引擎之前,最早js引擎是SpiderMonkey,第一个版本由js作者Brendan Eich设计,后交给Mozilla组织维护。js引擎在执行js文件时,都会先将js代码转换成抽象语法树(AST)。有一天,一位Mozilla工程师在FireFox中公开了这个将代码转成AST的解析器Api,也就是Parser_API,后来被人整理到github项目estree,慢慢的成了业界的规范。

七、 源码解读

待填坑


http://www.niftyadmin.cn/n/896.html

相关文章

2022-10-26 Unity 2进制1——文件操作

文章目录一、各类型数据和字节数据相互转换二、文件操作三、文件操作 File 类的常用内容​ 2 进制文件读写的本质就是通过将各类型变量转换为字节数组,将字节数组直接存储到文件中,一般人是看不懂存储的数据的​ 不仅可以节约存储空间,提升效…

AntDB-M设计之CheckPoint

1.引 言 数据库服务能力提升是一项系统性的工程,在不同的应用场景下,用户对于数据库各项能力的关注点也不同,如:读写延迟、吞吐量、扩展性、可靠性、可用性等等。国内不少数据库系统通过系统架构优化、硬件设备升级等方式&…

内网渗透体系学习4

在内网渗透中,当测试人员获取某台机器的控制权后,会以被攻陷的主机为跳板进 行横向渗透,进一步扩大所掌控的资源范围。但是横向渗透中的很多攻击方法都需要先 获取到域内用户的密码或哈希值才能进行,如哈希传递攻击、票据传递攻击…

YoloV5+ECVBlock:基于YoloV5-ECVBlock的小目标检测训练

目录 1、前言 2、数据集 3、添加ECVBlock 4、BackBone+ECVBlock 5、Head+ECVBlock 6、训练结果

HTML基础

目录 一,HTML结构 1.认识HTML标签 2.HTML文件基本结构 3.标签层次结构 (父子&兄弟) 二,HTML常见标签 1.注释标签 2.标题标签:h1~h6 3.段落标签:p 4.换行标签:br 5.格式化标签 (…

【UE】材质入门

材质 首先明确什么是物体的材质,材质属性定义了物体的某些特性,从而决定了物体表面是如何与光线相作用的。 本节只是简单介绍一下 UE 中材质创建和使用的方法 为了验证材质现在场景中添加一个 SM_MAT 意为静态网格物体 然后选一个合适的位置创建一个文…

qt实战-翻金币游戏

项目介绍 界面演示 规则说明 翻金币是一个简单的游戏,在翻金币场景中点击界面中的币可以进行翻转,翻转规则是币加其上下左右的币同时进行翻转(动画做了一些小延迟),胜利的条件是界面中全是金币。 实现步骤分解 由界…

[架构之路-57]:目标系统 - 平台软件 - 用户空间驱动与硬件抽象层HAL

目录 前言: 第1章 驱动程序功能设计 1.1 关于用户空间驱动 1.2 硬件驱动程序的四大功能概述 1.3 OAM管理面功能:站在管理源的角度,看如何监控使能和监控硬件。 1.4 控制面功能:站在业务的角度看,如何使能和监控硬…