规范
ECMAScript® 2023 语言规范详细介绍了 JavaScript 语言的方方面面,这样任何人都可以实现自己的 JavaScript 引擎。
以下章节需要为我们的解析器学习
- 第 5 章:符号约定
- 第 11 章:ECMAScript 语言:源代码
- 第 12 章:ECMAScript 语言:词法语法
- 第 13 - 16 章:表达式、语句、函数、类、脚本和模块
- 附录 B:Web 浏览器其他 ECMAScript 功能
- 附录 C:ECMAScript 的严格模式
用于规范内的导航
- 所有可点击内容均设有永久链接,它们在 URL 中显示为锚点,例如
#sec-identifiers
- 将鼠标悬停在内容上可能会显示一个提示框,点击“参考文献”可以显示其全部参考文献
符号约定
第 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]
意味着顶级生成器、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))
}
信息
本节关于 asi 的内容是针对编写解析器而写的,它明确指出源文本是从左到右进行解析的,这使得几乎不可能用任何其他方式编写解析器。jsparagus 的作者对此发表了一篇批评文章 在此。
此功能的规范一方面非常高层,另一方面又奇异地带有程序性(“当在从左到右解析源文本时,遇到令牌...”,仿佛该规范在讲述浏览器的故事。据我所知,这是规范中唯一假定或暗示解析内部实现细节的地方。)但是很难用其他方式指定 ASI。
表达式、语句、函数、类、脚本和模块
理解语法需要一段时间,然后运用这些语法编写解析器。