这是手写babel系列的第二讲。这一讲咱们来说说笼统语法树(AST)。今天是2024年 大年初一,在这里先祝咱们新年快乐,龙年行大运。
AST是干啥的?
它是咱们源代码的一种笼统表明
。更详细的来说便是运用树状结构去表明代码的语法结构
。
AST是怎么生成的?
它的形成能够分为3个进程,分别是 词法剖析
、语法剖析
、语义剖析
。
这里有一个问题,咱们需要了解这方面的知识吗?咱们拿到AST去做一些工作,能够使用AST可视化网站,这很方便的,比方下面这样:
我觉着是一定要了解的。功利性的来讲,如果你在面试进程中遇到了相关的问题,而如果你把AST可视化网站搬曩昔敷衍面试官的话,那大概率这个知识点你是不通过,虽然使用AST网站去做源代码转换的工作 这是一个事实。
词法剖析
这个进程首要便是读取代码,将代码都拆解成一个一个的最小单元(有人管它叫tokens,也有人管它叫做单词,叫啥不重要,能够知道它是AST的最小组成单元即可)。
语法剖析
在词法剖析的基础上,根据言语的语法规矩,剖析程序根本语法结构,并将最小单元组成树状结构。
语义剖析
这一步首要是用来检查源代码是否存在语法过错,如果有过错的话就直接抛出来。
怎么写一个最简单的babel插件
上面这个作为了解就能够了,不用过多深化。接下来咱们来看看怎么写一个babel插件。
还是一样,先打开AST可视化网站,然后选中transform选项,如下图:
咱们看到,左下方,默认就有一个babel插件。左上方是一段js源代码,右上方是源代码对应的AST。左上方的js源代码
通过 左下方的babel插件处理后
,生成了右下方的目标代码
。
那咱们接下来就一起讨论一下 这个babel插件是怎么编写的。
节点(node)
右上方是实时的AST,它里边的每个目标,都能够被叫做一个节点。
这些节点都有以下相似的结构:
{
type: "XXXXX",
name: ...,
id: {...},
params: [...],
left: {...},
right: {...},
body: {...}
}
上面的这些属性里,type字段是有必要要有的
,用来标识当时节点的类型。它是一个枚举,包括 XxDeclaration、XxStatement、XxExpression等等。
插件里的babel参数
export default function (babel) {
const { types: t } = babel;
return {
name: "ast-transform", // not required
visitor: {
Identifier(path) {
path.node.name = path.node.name.split('').reverse().join('');
}
}
};
}
首要,咱们看到,一个babel插件其实便是一个函数
,然后,这个函数需要回来一个目标obj
,obj需要具有一个访问者vistor属性
。这个vistor属性的值也是一个目标b
。目标b由不同的函数属性构成
。
babel参数其实指代的是 @babel/core
这个中心模块,里边包括了一些东西办法。比方babel.types
目标,这个目标里包括了很多的办法,支撑你去创立不同类型的节点。比方:babel.types.stringLiteral办法
用于创立一个字符串值。
本篇文章里暂时还用不到,后续文章会有讲到。
vistor访问者
它首要是用来处理节点的增修改查的。所以它是很重要的一个概念。咱们知道,节点的类型有很多种,你想要处理哪个,就要把这一类的节点类型写在一个函数里去处理。
以咱们这里为比如:
let tips = [];
咱们要写一个插件,用来将上述代码的 let
改为 const
,那咱们要怎么写呢?
首要,将咱们的代码放到 AST可视化网站上,随后,咱们应该有如下思路:
- let这个关键字,关于AST来说,它也是一个节点。
- 已然let都是一个节点了,那const也应该是一个节点。
- 这个需求其实也便是替换节点。
- 替换节点的代码位置应该在哪里呢?刚才咱们讲过,vistor便是干这个事的。
- 怎么写呢?咱们刚才也说过,你要把同一个类型的节点处理写在一个函数里。
- 那我怎么知道let归于哪个类型的节点?AST可视化网站不就派上用场了嘛。你把上面的代码放到这个可视化网站里看一下不就知道啦。
- 通过检查得知,
let
的节点类型 是VariableDeclaration
。
于是,咱们就能够写出下面的babel插件:
export default function (babel) {
const { types: t } = babel;
return {
name: "ast-transform", // not required
visitor: {
VariableDeclaration(path){
path.node.kind = 'const';
}
}
};
}
最终发现,咱们如约的完成了这个需求。
最终
好啦,本期babel共享到这里就结束啦,希望我的共享能够对你有协助,咱们下期再见啦~~