简易 JS 引擎实现思路分析 Parser 可以是任意的 JS Parser,我们直接用 @babel/parser。...自然可以想到,解释 ObjectExpression 节点就是取出 AST 中的数据构造一个对象返回: 再比如 let a = { n: 1} 这条赋值语句,它对应的是 VariableDeclaration...节点,下面有多个 VariableDeclarator 子节点,这是因为一条声明语句可以声明多个变量,比如 let a = 1, b =1; 而具体的声明 VariableDeclarator 里分别有...声明语句的解释就是在作用域(我们声明的 Map)中设置下就行: VariableDeclaration(node) { node.declarations.forEach((item) => {...具体的声明 VariableDeclarator 就是在 scope 中设置变量名和它的值。 变量名是 node.id 的执行结果,如果声明过就报错,因为只能声明一次。
个人学习也是如此,养成定期学习的习惯,比在培训班突击几个月更有用,学会在生活中规律的学习,甚至好过读几年名牌大学。...所以我们的目的并不是像文章标题说的 - 创造一个自定义 JS 语法,因为你创造的语法只会让 JS 复杂体系更加混乱,但可以让你理解 Babel 解析标准 JS 语法的原理,以及看待新语法提案时,拥有从实现层面思考的能力...由于 @@ 是我们创造的语法,所以我们第一个任务就是让 babel 词法分析可以识别它。...语法 词法已经可以将 @@ 解析为 atat Token,下一步我们就要利用这个 Token,让生成的 AST 结构中包含柯里化函数的信息,并利用 babel 插件在解析时实现柯里化功能。...同理,增加一个 curry 属性就可以实现第一步了: 要实现如上效果,只需在词法分析 parser/statement 文件的 parseFunction 处新增 atat 解析即可: // packages
做与不做 注意很重要的一点就是,Babel 只是转译新标准引入的语法,比如: 箭头函数 let / const 解构 哪些在 Babel 范围外?...整个解析过程分为两个步骤: 分词:将整个代码字符串分割成语法单元数组 语法分析:建立分析语法单元之间的关系 分词 语法单元通俗点说就是代码中的最小单元,不能再被分割,就像原子是化学变化中的最小粒子一样...语义分析则是将得到的词汇进行一个立体的组合,确定词语之间的关系。...考虑到编程语言的各种从属关系的复杂性,语义分析的过程又是在遍历得到的语法单元组,相对而言就会变得更复杂。...简单来说语法分析是对语句和表达式识别,这是个递归过程,在解析中,Babel 会在解析每个语句和表达式的过程中设置一个暂存器,用来暂存当前读取到的语法单元,如果解析失败,就会返回之前的暂存点,再按照另一种方式进行解析
有了这棵树,我们就可以通过操纵这颗树,精准的定位到声明语句、赋值语句、运算语句等等,实现对代码的分析、优化、变更等操作。...用一个叫做jsparser的工具来转化, 整个解析过程主要分为以下两个步骤: 分词:将整个代码字符串分割成最小语法单元数组 语法分析:在分词基础上建立分析语法单元之间的关系 什么是语法单元呢?...然后就是语法分析,上面我们已经得到了我们分词的结果,需要将词汇进行一个立体的组合,确定词语之间的关系,确定词语最终的表达含义。简单来说语法分析是对语句和表达式识别,确定之前的关系,这是个递归过程。...上面我们通过语法分析,可以得到如下结果: { "type": "Program", "body": [ { "type": "VariableDeclaration...js,这里就可以进行一些操作了,我们可以修改抽象语法树,然后再将其转化为js语言,这样就达到了将某一个版本的js转化为另外一个版本的js的作用。
前言:做基础技术的时候,会经常碰到一个问题就是如何让自己提供的代码对用户少侵入,无感。...比如我提供了一个 SDK 收集 Node.js 进程的 HTTP 请求耗时,最简单的方式就是给用户提供一个 request 方法,然后让用户统一调用,这样我就可以在 request 里拿到这些数据。...在 Node.js 中,统计 JS 函数的耗时通常的做法是 cpu profile,但是这种方式只能拿到一段时间的耗时,如果我想实时收集耗时数据,cpu profile 就有点难搞,最直接的就是定时收集...entryNode = b.variableDeclaration('const', [b.variableDeclarator(b.identifier('start'), b.callExpression...不过这种方式的难点在重写代码的逻辑,风险也比较大,但是如果我们解决了这个问题后,我们就可以随便 hack 用户的代码,做我们想做的事情,当然,是正事。
AST 结构 随着 JavaScript 的发展,为了统一ECMAScript标准的语法表达。社区中衍生出了ESTree Spec,是目前社区所遵循的一种语法表达标准。...函数体中: 声明了一个const类型变量a,值为 1 执行了一个 console.log 语句 将上述代码粘贴至AST Explorer,结果如图所示: 3.png 接下来我们继续分析内部结构,以const...a = 1为例: 4.png 变量声明在 AST 中对应的就是 type 为VariableDeclaration的节点。...而 type 为VariableDeclarator的节点代表的就是a=1这种声明语句,其中包含id和init属性。 id即为Identifier,其中的name值对应的就是变量名称。...Babel 概述 Babel 是一个 JavaScript 编译器,在实际开发过程中通常借助Babel来完成相关 AST 的操作。
在 Vscode 新建一个 launch.json ,选择 Node.js 。 把默认生成的 program 字段去掉,加上 args 。...强烈推荐先过去 看一下,对 babel 可以有一个更直接的了解。...一个编译器主要是三个步骤,解析(词法分析、语法分析)-> 转换 -> 生成目标代码。 第一步「解析」就是去生成一个 AST,主要分两步。...(AST) 通过上边分词,然后就可以生成一个 AST 树 { "type": "Program", "body": [ { "type": "VariableDeclaration",...同理,对于 VariableDeclarator 节点,它可以枚举的 key 就是 ['id', 'init']。
利用这个网站来分析下两端代码的AST有什么不同: 第一段代码的AST: // 源代码的 AST { "type": "Program", "start": 0, "end": 21...我们在修改第一段代码的AST时着重修改这里,如何修改呢?...transform 方法,它可以将 js 代码转换成 AST ,过程中可以通过使用 plugins 对 AST 进行改造,最终生成新的 AST 和 js 代码,其整个过程用网上一个比较贴切的图就是:...}, leave(node){ } } } 这里我们使用第一种: 通过分析目标代码的 AST,我们发现,需要一个 FunctionExpression...参照 AST 我们可以看到其 id 为 null,params 是原 ArrowFunctionExpression 中的 params,body 是一个blockStatement,我们也可以通过查看
前言 前面写过一篇简单的 AST 抽象语法树的文章简述 AST 抽象语法树。今天来看一下在 babel 中是如何将 ES6 转换为 ES5 的 。...在 webpack 中 babel-loader 就是通过这个包实现。babylon:babel 的词法解析器。将原始代码逐个字母地像扫描机一样读取分析得出 AST 语法树结构。...babel-polyfill:JS 标准新增的原生对象和 API 的 shim,实现上仅仅是 core-js 和 regenerator-runtime两个包的封装。...es2017 / env / stage-0 / stage-4 其中 es20xx 表示转换成该年份批准的标准,env 是最新标准,stage-0 和 stage-4 是实验版)转换成新的 AST...plugins 和 presets 通常在 .babelrc 文件中配置。 3. Generator 生成 第三步是将新的 AST 语法树对象再生成浏览器都可以识别的 ES5 语法。
[03] 语法分析 语法分析是编译过程的一个逻辑阶段,语法分析的任务是在词法分析的基础上将单词序列组合成各类语法短语,比如“程序”,“语句”,“表达式”等,前面的例子中,isPanda('') 就会被分析为一条表达语句...,其值有数字也有字符串,我们在 AST 中可以看到对应的类型为 NumericLiteral 和 StringLiteral: [09] 然后我们声明了一个 visitor 对象,然后定义对应类型的处理方法...首先观察一下 AST 语法树,原语句只有一个 VariableDeclaration 节点,现在增加了一个: [10] 那么我们的思路就是在遍历节点时,遍历到 VariableDeclaration 节点...,就在其后面增加一个 VariableDeclaration 节点,生成 VariableDeclaration 节点,可以使用 types.variableDeclaration() 方法,在 types...是 VariableDeclarator 类型的节点组成的列表,所以我们可以先写出以下 visitor 部分的代码,其中 path.insertAfter() 是在该节点之后插入新节点的意思: const
callee 属性是一个表达式节点,表示函数,arguments 是一个数组,元素是表达式节点,表示函数参数列表.图片MemberExpression(成员表达式节点):即表示引用对象成员的语句,object...图片VariableDeclarator(变量声明的描述):id 表示变量名称节点,init 表示初始值的表达式,可以为 null图片IfStatement(if表达式):if(true),test 属性表示...访问者模式,即将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式,简单来说,就是定义了用于在一个树状结构中获取具体节点的方法...从而可以避免在 npm 仓库中 babel 相关名称被抢注的问题,并且采用了Babel Monorepo风格的仓库。...@babel/types:用于检验、构建和改变AST树的节点@babel/cli 是 Babel 提供的命令行,它可以在终端中通过命令行方式运行,编译文件。
浏览器在解析 JS 的过程中,会根据 ECMAScript 标准将字符串进行分词,拆分为一个个语法单元。然后再遍历这些语法单元,进行语义分析,构造出 AST。...三、Babel 工作原理 AST 除了可以转换为机器码外,还能做很多事情,如 Babel 就能通过分析 AST,将 ES6 的代码转换成 ES5。...const declarator = t.variableDeclarator(id, literal) // 生成 variableDeclaration const declaration =...t.variableDeclaration('const', [declarator]) // 将表达式放入body中 ast.program.body.push(declaration) const...掌握这项技能,再加上一点想象力,就能制作出实用的代码分析和转换工具。
即便你的程序也许在运行时报错,但都不会影响 AST 解析(除非语法错误),在 js 逆向中,通过静态分析还原出相对容易看的出的代码有对于代码分析,而对于一些需要知道某一变量执行后的结果静态分析是做不到的...>): VariableDeclaration 可以看到第一个参数就是关键字,而第二个则一个数组,其中节点为VariableDeclarator,关于variableDeclaration与 VariableDeclarator...由于我们这里只是声明一个变量 a,所有数组成员只给一个便可,如果要生成 b,c 这些变量,就传入对应的VariableDeclarator即可 这时候在查看下 VariableDeclarator 方法参数...在查看 numericLiteral 中的参数,就只给一个数值,那么便传入 100。...binding scope.getBinding() 接收一个参数,可用于获取标识符的绑定,这里的 binding 可能会有些抽象,在一开始的例子中初次接触到 traverse(ast, { VariableDeclarator
起因 白帽子们挖Web漏洞时,JavaScript信息是至关重要的一环 从JS中可以得到隐藏接口等信息,然后尝试挖掘越权,SQL注入和上传等洞 笔者刚入门时候曾用这种办法挖到了一些CNVD,算是收获颇丰...,不过我不太懂JS,第一次遇到感觉挺有趣的 起因是发现调试该JS时候会发现卡死,但目标网站在正常使用该JS脚本 分析 做全局JavaScript做了一定的分析后,最终跟踪到代码如下 注意到其中有类似正则的地方...*}因此返回false 继续看后面的表达式,如果为true会从NsTJKl数组中移除1否则移除0,暂不分析这里的用途 this['NsTJKl'] = [0x1, 0x0, 0x0]; 函数的return...,本质是一处的正则没有匹配到 问题来了,为什么目标网站的正则可以匹配到,但我本地无法匹配到 原因不难,目标网站的JS是压缩后的代码 this['HILIkx'] = function () {return...'newState';}; 逆向者在本地尝试做破解的时候,会将代码格式化(无论chrome还是vscode里都会很容易地进行格式化) 格式化后的代码不满足条件,所以会进入死循环 绕过方式其实也简单,还原回压缩格式即可
在根目录新建一个 cli.js ,并且赋予执行权限,执行 chmod +x ./cli.js ,输入下边的内容: #!...通过 optimist 解析,我们就可以得到相应的 key 、value 键值对了。 esprima 可以做词法分析或者生成 AST 的语法树,直接看示例。 #!...原理 知道了 AST 树,我们其实就可以实现最简单的 Eslint 检查了,比如最常见的是否使用了 ===。 举个例子,对于 answer == 42; 我们在 walk 过程中会得到这样一个节点。...EventEmitter 库 一个 Ast 节点对应一个要处理的规则,每遍历一个节点,就去处理相应的规则。...,更细节的内容可以在本地 git clone git@github.com:eslint/eslint.git 并且 git checkout v0.0.2 看。
在英语中,当我们遇到这样一个语句时: Javascript is the best language in the world 我们会下意识地把句子分解成一个个单词: +---------------...": Subject "is the best language": Predicate "language": Object Javascript 在语法中是一个主语名词,其余的是一个没有什么意义的句子叫做谓语...我们可以看到这段代码中存在 4 种节点类型,下面我们简单的介绍一下它们: Program 根节点,即代表一整颗抽象语法树,body 属性是一个数组,包含了多个 Statement 节点。...从语法树中我们可以看到三个陌生的节点类型,来看看它们分别代表什么意思: VariableDeclaration 变量声明,kind 属性表示是什么类型的声明,因为 ES6 引入了 const/let。...},块里边可以包含多个其他的语句,所以有一个 body 属性,是一个数组,表示了块里边的多个语句。
,是前端工程化绕不过的一个名词。...SFC 等等 而在语言转换的过程中,实质上就是对其 AST 的操作,核心步骤就是 AST 三步走 Code -> AST (Parse) AST -> AST (Transform) AST -> Code...在 AST Explorer 中,列举了诸多语言的解析器(Parser),及转化器(Transformer)。...AST 的生成 AST 的生成这一步骤被称为「解析(Parser)」,而该步骤也有两个阶段: 词法分析(Lexical Analysis)和语法分析(Syntactic Analysis) 词法分析 (...Lexical Analysis) 词法分析用以将代码转化为 Token 流,维护一个关于 Token 的数组 // Code a = 3 // Token [ { type: { ... },
我们可以在 https://babel.docschina.org/repl 尝试一下。 一个小?...为 add 的ArrowFunctionExpression(箭头函数): params(函数入参):a 和 b 函数体:函数主体是一个BinaryExpression(二项式),一个标准的二项式分为三部分...词法分析 词法分析阶段可以看成是对代码进行“分词”,它接收一段源代码,然后执行一段 tokenize 函数,把代码分割成被称为Tokens 的东西。...语法分析 词法分析之后,代码就已经变成了一个 Tokens 数组了,现在需要通过语法分析把 Tokens 转化为上面提到过的 AST。 说来惭愧,这里没有想到很好的思路来实现一个 parse 函数。...所以,操作 AST 也就是操作其中的节点,可以增删改这些节点,从而转换成实际需要的 AST。 更多的节点规范可以在https://github.com/estree/estree中查看。
修改函数名字 此时我们发现函数的名字在 type 为 Identifier 的时候就是该函数的名字,我们就可以直接修改它便可实现一个更改函数名字的 AST 工具 ?...,说白了其实就是拼成另一颗树的结构,然后生成新的代码,就可以完成代码的转换 访问者模式 在 babel 中,我们开发 plugins 的时候要用到访问者模式,就是说在访问到某一个路径的时候进行匹配,然后在对这个节点进行修改...我们细看 AST 结构,函数表达式中的 BlockStatement 中的 body 是一个 ReturnStatement,所以我们还需要生成一个 ReturnStatement 现在我们就可以改写...) 那我们要做的就很简单了,就是把 数组表达式转换为调用表达式就可以 分析类型 这段代码的核心生成一个 callExpression 调用表达式,所以对应官网上的类型,我们分析需要用到的 api 先来分析...一般的,在源代码的翻译和编译过程中,语法分析器创建出分析树。一旦 AST 被创建出来,在后续的处理过程中,比如语义分析阶段,会添加一些信息。可参考抽象语法树和具体语法树有什么区别?
callee 属性是一个表达式节点,表示函数,arguments 是一个数组,元素是表达式节点,表示函数参数列表MemberExpression(成员表达式节点):即表示引用对象成员的语句,object...VariableDeclarator(变量声明的描述):id 表示变量名称节点,init 表示初始值的表达式,可以为 null IfStatement(if表达式):if(true),test 属性表示...访问者模式,即将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式,简单来说,就是定义了用于在一个树状结构中获取具体节点的方法...从而可以避免在 npm 仓库中 babel 相关名称被抢注的问题,并且采用了Babel Monorepo风格的仓库。...@babel/types:用于检验、构建和改变AST树的节点@babel/cli 是 Babel 提供的命令行,它可以在终端中通过命令行方式运行,编译文件。
领取专属 10元无门槛券
手把手带您无忧上云