规范
ECMAScript® 语言规范(一个活标准)详细介绍了 JavaScript 语言的一切,因此任何人都可以实现自己的 JavaScript 引擎。
我们的解析器需要研究以下章节:
- 第 5 章:表示约定
- 第 11 章:ECMAScript 语言:源文本
- 第 12 章:ECMAScript 语言:词法语法
- 第 13 - 16 章:表达式、语句、函数、类、脚本和模块
- 附录 B:面向 Web 浏览器的额外 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
本节关于 asi 的内容是考虑到解析器而写的,它明确指出源文本是从左到右解析的,这使得几乎不可能以其他方式编写解析器。jsparagus 的作者对此发表了一篇牢骚 这里。
该特性的规范既非常高层又奇怪地过程化(“当源文本从左到右解析时,遇到一个标记...",就好像规范在讲述一个关于浏览器的故事。据我所知,这是规范中唯一假设或暗示关于解析内部实现细节的地方。)但很难用其他方式指定 ASI。
表达式、语句、函数、类、脚本和模块
理解句法语法需要花费一些时间,然后将它们应用于编写解析器。
