规范
ECMAScript® 2023 语言规范 详细描述了 JavaScript 语言的方方面面,因此任何人都可以实现自己的 JavaScript 引擎。
在编写我们的解析器时,需要学习以下章节:
- 第 5 章:符号约定
- 第 11 章:ECMAScript 语言:源代码文本
- 第 12 章:ECMAScript 语言:词法语法
- 第 13 至 16 章:表达式、语句、函数、类、脚本和模块
- 附录 B:面向网络浏览器的额外 ECMAScript 特性
- 附录 C:ECMAScript 的严格模式
在规范内部导航时:
- 所有可点击的内容都有永久链接,它们会作为锚点显示在 URL 中,例如
#sec-identifiers - 悬停在内容上可能显示提示信息,点击
References可查看所有引用项
符号约定
第 5.1.5 节 语法符号 是我们需要阅读的部分。
这里需要注意以下几点:
递归
这是语法中表示列表的方式。
ArgumentList :
AssignmentExpression
ArgumentList , AssignmentExpression表示
a, b = 1, c = 2
^_____________^ ArgumentList
^__________^ ArgumentList, AssignmentExpression,
^___^ AssignmentExpression可选
可选语法使用 _opt_ 后缀。例如,
VariableDeclaration :
BindingIdentifier Initializer_opt表示
var binding_identifier;
var binding_identifier = Initializer;
______________ Initializer_opt参数
[Return] 和 [In] 是语法的参数。
例如
ScriptBody :
StatementList[~Yield, ~Await, ~Return]表示脚本中不允许顶层的 yield、await 和 return,但
ModuleItem :
ImportDeclaration
ExportDeclaration
StatementListItem[~Yield, +Await, ~Return]允许顶层的 await。
源代码文本
第 11.2 节 源代码类型 告诉我们, 脚本代码和模块代码之间存在巨大差异。 此外,use strict 模式通过禁止旧版 JavaScript 行为,使语法更清晰。
脚本代码 不是严格的,必须在文件顶部插入 use strict 才能使脚本代码进入严格模式。 在 HTML 中我们编写 <script src="javascript.js"></script>。
模块代码 默认是严格的。 在 HTML 中我们编写 <script type="module" src="main.mjs"></script>。
ECMAScript 语言:词法语法
如需更深入的解释,请阅读 V8 博客中的 理解 ECMAScript 规范。
自动分号插入
本节描述了在编写 JavaScript 时可以省略分号的所有规则。 所有说明都归结为:
pub fn asi(&mut self) -> Result<()> {
if self.eat(Kind::Semicolon) || self.can_insert_semicolon() {
return Ok(());
}
let range = self.prev_node_end..self.cur_token().start;
Err(SyntaxError::AutoSemicolonInsertion(range.into()))
}
pub const fn can_insert_semicolon(&self) -> bool {
self.cur_token().is_on_new_line || matches!(self.cur_kind(), Kind::RCurly | Kind::Eof)
}asi 函数需要在适当位置手动调用,例如在语句末尾:
fn parse_debugger_statement(&mut self) -> Result<Statement<'a>> {
let node = self.start_node();
self.expect(Kind::Debugger)?;
self.asi()?;
self.ast.debugger_statement(self.finish_node(node))
}INFO
本节关于自动分号插入的描述是针对解析器而言的, 它明确指出源代码是从左到右进行解析的, 这几乎使得以其他方式编写解析器变得不可能。 jsparagus 的作者对此发表过一番牢骚 这里.
这一功能的规范既高度抽象又奇怪地采用过程式描述(“当从左到右解析源代码时,遇到一个标记……”),仿佛规范是在讲述一个浏览器的故事。据我所知,这是规范中唯一一处对解析的内部实现细节做出假设或暗示的地方。但恐怕很难用别的方式描述 ASI。
表达式、语句、函数、类、脚本和模块
理解语法结构需要一些时间,然后才能将其应用于解析器的编写。
