抽象语法树AST以及babel原理
什么是AST?
借用一下百度百科的解释:
在计算机科学中,抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。
其实意思就是将代码以树的格式展现出来,举个例子你就明白了:
大家可以在这个网站 https://astexplorer.net/ 上输入代码,会被解析为 AST,如图:
可以看到,代码的每一个字符都以树的形式展示了出来。
AST的应用场景
常见的场景:
- IDE的错误提示、代码格式化、代码高亮、代码自动补全等
- JSLint、JSHint对代码错误或风格的检查等
- webpack、rollup进行代码打包等
- CoffeeScript、TypeScript、JSX等转化为原生Javascript、babel把es6转换成es5语法
代码执行的步骤
从js程序到机器可执行的机器码需要经历两个阶段:
- 语法检查(源代码 -> 抽象语法树AST)
- 词法分析(源代码 -> Token序列)
- 语法分析(Token序列 -> 抽象语法树AST)
- 编译运行(抽象语法树AST -> 机器码)
1、词法分析
源代码 -> Token序列
将整个代码字符串分割成最小语法单元数组,也就是一个个的标识Tokens(type 和 value )。
https://esprima.org/demo/parse.html#
[{"type": "Keyword","value": "var"},{"type": "Identifier","value": "a"},{"type": "Punctuator","value": "="},{"type": "Numeric","value": "1"},{"type": "Punctuator","value": ";"}
]
常见的type:
Keyword (关键词)
Identifier (标识符)
Punctuator (标点符号)
Numberic(数字)
String (字符串)
Boolean(布尔)
Null(空值)
2、语法分析
Token序列 -> 抽象语法树
{// 表示是一段程序代码"type": "Program",// 代码的具体内容"body": [{// 表示这个内容块是干什么的"type": "VariableDeclaration",// 装变量内容的块"declarations": [{// 声明的类型是个变量"type": "VariableDeclarator",// 表示变量名"id": {"type": "Identifier","name": "a"},// 表示为这个变量设置的初值"init": {"type": "Literal","value": 1,"raw": "1"}}],"kind": "var"}],// 表示语言的种类"sourceType": "script"
}
3、编译运行
这个阶段会处理AST,生成机器可执行的机械码。
举个例子
上面讲了 AST 可以对代码进行转换,那么我们举个例子详细说明一下。
比如我们要实现:
- 将源代码中的
==
变成===
- 将源代码中的 var 变成 let
- 将源代码中的 console注释掉
这个例子用到的工具:
- esprima(源代码 -> 抽象语法树AST)
- estraverse(遍历AST)
- escodegen(将AST反编译为js代码)
originCode.js 为要转换的源代码
function fun() {var opt = 1;console.log(1);if (opt == 1) {console.log(2);}
}
index.js 是我们要执行的 node 文件
let fs = require('fs');
const esprima = require('esprima');//将JS代码转化为语法树模块
const estraverse = require('estraverse');//JS语法树遍历各节点
const escodegen = require('escodegen');//将JS语法树反编译成js代码模块/**
* 由源代码得到抽象语法树
*/
function getAst(jsFile) {let jsCode;return new Promise((resolve)=>{fs.readFile(jsFile, (error, data) => {jsCode = data.toString();resolve(esprima.parseScript(jsCode));});});
}/*** 设置全等*/
function setEqual(node) {if (node.operator === '==') {node.operator = '===';}
}/*** 删除console*/
function delConsole(node) {if (node.type === 'ExpressionStatement' && node.expression.type === 'CallExpression' && node.expression.callee.object.name==='console') {node.expression.callee.object.name = '//console';}
}/*** 把var变成let*/
function setLet(node){if(node.kind === 'var'){ node.kind = 'let';}
}/*** 遍历语法树*/
function travel(ast){estraverse.traverse(ast, {enter: (node) => {setEqual(node);setLet(node);delConsole(node);}});
}/**
* 生成文件
*/
function writeCode(file,data) {fs.writeFile(file,data,(error)=>{console.log(error);});
}/**
* 入口函数
*/
function main(){let file = './originCode.js';let distFile = './distCode.js';getAst(file).then(function(jsCode) {travel(jsCode);// 删掉 console , 通过parseScript在生成一变ast去掉注释的内容// let distCode = escodegen.generate( esprima.parseScript( escodegen.generate(jsCode)));// 注释 consolelet distCode = escodegen.generate(jsCode);console.log('distcode',distCode);writeCode(distFile,distCode);});
}main();
执行
node index.js
得到的结果 distCode.js
function fun() {let opt = 1;//console.log(1);if (opt === 1) {//console.log(2);}
}
总结
再看一遍这个流程:
源代码 -> 抽象语法树AST -> 机器码/新的js
从上面的这个例子可以看出,我们可以通过修改 AST,从而修改成我们想要的结果,那么像IDE代码高亮、代码混淆压缩、Babel es6转es5、ts转js等等就很好理解了。
babel原理
babel 原理也是 AST,babel 有许多工具可以直接使用,如下:
babel把es6转换成es5语法的原理?
- 解析(parse)。将源代码解析变成AST。@babel/parser模块
- 转换(transform)。对AST 进行遍历,在此过程中对节点进行添加、更新及移除等操作。因此这是bebel处理代码的核心步骤,是我们的讨论重点,主要使用@babel/traverse和@babel/types模块。
- 生成(generate)。将更改后的AST,再变回代码。@babel/generate模块。
举例:将 var 变为 let
const generator = require('@babel/generator');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse');
const transToLet = code => {const ast = parser.parse(code);// 访问者对象const visitor = {// 遍历声明表达式VariableDeclaration(path) {if (path.node.type === 'VariableDeclaration') {// 替换if (path.node.kind === 'var') {path.node.kind = 'let';}}},};traverse.default(ast, visitor);// 生成代码const newCode = generator.default(ast, {}, code).code;return newCode;
};const code = `const a = 1
var b = 2
let c = 3`;
transToLet(code);
结果
const a = 1;
let b = 2;
let c = 3;
参考资料
AST规范
抽象语法树AST以及babel原理相关推荐
- 理解Babel是如何编译JS代码的及理解抽象语法树(AST)
Babel是如何编译JS代码的及理解抽象语法树(AST) 1. Babel的作用是? 很多浏览器目前还不支持ES6的代码,但是我们可以通过Babel将ES6的代码转译成ES5代码,让所有的浏览器 ...
- 什么是抽象语法树(AST)
原创: 弗拉 码农翻身 作者: 弗拉@重度前端 https://segmentfault.com/a/1190000017992387 已经获得作者独家授权发布,老刘做了改编. 张大胖一上班,领导就扔 ...
- java抽象语法树(ast),【你应该了解的】抽象语法树AST
团队:skFeTeam 本文作者:李世伟 作为前端程序员,webpack,rollup,babel,eslint这些是不是经常用到?他们是打包工具,代码编译工具,语法检查工具.他们是如何实现的呢?本 ...
- php7 ast,PHP7新特性之抽象语法树(AST)带来的变化详解
本文分析了PHP7新特性之抽象语法树(AST)带来的变化.分享给大家供大家参考,具体如下: 这里大部分内容参照 AST 的 RFC 文档而成:https://wiki.php.net/rfc/abst ...
- 【编译原理】构建一个简单的解释器(Let’s Build A Simple Interpreter. Part 7.)(笔记)解释器 interpreter 解析器 parser 抽象语法树AST
[编译原理]让我们来构建一个简单的解释器(Let's Build A Simple Interpreter. Part 7.) 文章目录 python代码 插--后序遍历 C语言代码(有错误) C语言 ...
- js最小化浏览器_「译」解析、抽象语法树(ast) +如何最小化解析时间的5个技巧...
前言 该系列课程会在本周陆续更新完毕,主要讲解的都是工作中可能会遇到的真实开发中比较重要的问题以及相应的解决方法.通过本系列的课程学习,希望能对你日常的工作带来些许变化.当然,欢迎大家关注我,我将持续 ...
- php ast 抽象语法树,抽象语法树(AST)
抽象语法树入门到放弃? 抽象语法树(Abstract syntax tree AST)在计算机科学中,抽象语法和抽象语法树其实是源代码的抽象语法结构的树状表现形式 为什么是抽象的? 前端工程化,离不了 ...
- 高级前端基础-JavaScript抽象语法树AST
前言 Babel为当前最流行的代码JavaScript编译器了,其使用的JavaScript解析器为babel-parser,最初是从Acorn 项目fork出来的.Acorn 非常快,易于使用,并且 ...
- JS抽象语法树AST基础学习
点击上方"Python学习开发",选择"加为星标" 第一时间关注Python技术干货! 原文:http://www.goyth.com/2018/12/23/A ...
最新文章
- 命名规则标识符 unix_关于全局唯一标识符
- MyBatis-06 MyBatis XML方式之多个接口参数用法
- [SAP ABAP开发技术总结]动态语句、动态程序
- tmemo 选择消除行_Divi模块,行和部分加入高级动画选项
- 最全面试考点与面试技巧,大厂面经合集
- 自动组卷系统C语言,模块化思想在试题库组卷系统中的应用--以C语言程序设计课程为例 (1).pdf...
- 小明刚刚看完电影《第39级台阶》离开电影院的时候,他数了一下礼堂前的台阶,刚好是39级 站在台阶前,他突然又想到了一个问题 如果我每步只能迈上一个或者两个台阶,先迈左脚,然后左右交替,也就是说一共
- 原生JS实现一个无缝轮播图插件(支持vue)
- 遥感方向SCI期刊整理
- 计算机毕业设计JavaWeb企业客户管理系统(源码+系统+mysql数据库+lw文档)
- Spring Boot HTTP over JSON 的错误码异常处理
- html table 内外边框,HTML_TABLE内外边框
- Paddle 点灯人 之 Tensor
- Vector-常用CAN工具 - CANoe入门到精通_01
- 基于GMapping的栅格地图的构建
- 基于esky实现python应用的自动升级
- 【时间序列】TFT:Temporal Fusion Transformers
- python换零钱_LeetCode-python 322.零钱兑换
- 【西语】【5】Qué clase de persona eres 你是什么样的人
- set_xscale 表示x轴缩放比例,一张图明明白白