AST初探

前端开发中,使用了很多工具,譬如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.png

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

代码:

function foo(a) {
    let b = a + 3;
    return b;
}

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

blockstatement 块级作用域。

VariableDecalaration 变量声明

VariableDecalarator 变量声明器

Returnstatement 返回语句

图片2.png

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

二、 语法树的应用

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

话不多说,看图。

图片3.png

这是一个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;“。

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

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 可视化查看词法分析结果。

图片4.png

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

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

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

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

es6 语法树:

图片5.png

es5语法树:


图片6.png

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

四、语法树的遍历和更改

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

const prima = require('esprima');
const codegen = require('escodegen');
const traverse = require('estraverse');
var  code2 = 'let a = 2';

五、生成 es5 代码

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

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,慢慢的成了业界的规范。

七、 相关推荐

从零实现一个简易编译器:https://github.com/YongzeYao/the-super-tiny-compiler-CN

Babel 插件和 ast 转化过程:https://juejin.cn/post/6844903992762318855

Babel 介绍:https://juejin.cn/post/6844903746804137991

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容