详细说明见 你好,JS 解释器
在生成语法树前,需要先进行分词
Token
通过模块acorn将JS代码解析为AST树。
如将代码段解析为如下结构:
let a = 1;{
"type": "Program",
"start": 0,
"end": 10,
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 10,
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 9,
"id": {
"type": "Identifier",
"start": 4,
"end": 5,
"name": "a"
},
"init": {
"type": "Literal",
"start": 8,
"end": 9,
"value": 1,
"raw": "1"
}
}
],
"kind": "let"
}
],
"sourceType": "module"
}在每一个新的块中需要创建新的作用域
JS中作用域主要分为三个部分:
- 全局作用域
- 函数作用域
- 块作用域
本解释器中,作用域中存储相关的变量信息,包含declare,get,set三个部分。
针对var const let三类变量进行存储,各自具备各自的声明与使用特点。
- 允许重复声明
- 声明提前至函数作用域或全局作用域
- 全局作用域下变量直接赋值,则当作
var处理
- 不允许重复声明
- 不允许重新赋值
- 不能声明提前
- 不允许重复声明
- 不能声明提前
本解释器中处理以下几类函数:
- 普通函数
function() {} - 箭头函数
() => {} - 异步函数
async function() {} - 生成器函数
funtion* (){}
对于函数的处理,需创建新的函数返回,在新的函数中对原函数进行调用。
额外注意:
- 参数的处理,创建新的作用域,当前作用域
return的处理,在递归中将return返回- 箭头函数的返回方式有两种
异步函数将基于 Generator 来实现,处理async和await字段。
通过asyncToGenerator函数来同步执行异步函数,见lib.js。
生成器的实现直接借用 API 来完成,处理yield和function *{}。
生成器的特点在于中断和恢复,即中断当前执行环境,恢复上一次的执行环境。
正因此,
yield不能像return一样前提,需要将递归函数同样封装为generator
gen.next()返回值为如下对象:
{
value: "xx",
done: false // true
}