为什么 "throw" 是自动分号插入的限制产生式?

Why is "throw" a restricted production for automatic semicolon insertion?

JavaScript 的部分自动分号插入算法就是所谓的 "restricted productions"。这些是禁止在特定点出现换行符的语法形式。引用 ECMAScript 2015 规范:

If the phrase “[no LineTerminator here]” appears in the right-hand side of a production of the syntactic grammar, it indicates that the production is a restricted production: it may not be used if a LineTerminator occurs in the input stream at the indicated position.

ECMAScript 2015 规范中有 10 个限制产生式:

在这些作品中,我理解对其中大部分进行限制的选择。 PostfixExpression 的产生式被限制以防止与 PrefixExpression 的解析歧义。 ContinueStatementBreakStatementReturnStatement 有限制产生式,因为有相应的产生式 break并且 continue 不带标签并且 return 不带表达式。我不能说我对箭头函数或 yield 表达式了解得足够多以知道为什么它们受到限制,但我认为这是为了防止某种类似的解析歧义。

我不明白的产生式是ThrowExpression。据我所知,使用 throw 不会像使用 breakreturncontinue 时那样出现解析歧义:毕竟,throw; 无效 JavaScript。我认为这可能是出于历史原因,但据我所知,throw; 从未在任何 JavaScript 规范中被允许。

这样做的实际结果与 return 非常相似,您不能将抛出的表达式放在下一行,例如这是错误的:

throw
new Error("some error");

但是,与 return 不同,这与将 new Error() 放在同一行没有不同的行为。这只是一个语法错误:Chrome 将其报告为

Uncaught SyntaxError: Illegal newline after throw

ThrowExpression 的产生式是否受到限制只是为了保持与类似结构的一致性?还是有一些我没有看到的歧义?

我认为 是正确的:与 return 一样,throw 的操作数本身通常是一个有效的表达式。 return \n "valid on its own"; 的问题是 ASI 问题最常见的例子之一,因此限制 return 和任何其他采用类似值的语句是一种合理的保护措施。

查看列表,其中大部分是一元运算符(或者看起来就像一个)。它们都遵循相同的一般形式,除了箭头函数。这种形式是 ASI 错误的一个原因,因此限制整个类别比仅 return.

更可预测

我们只能在这里猜测为什么 语言作者决定这样做,但我想说这是为了与 return 保持一致。 return ¶ valuethrow ¶ value 都是禁止的,如果你想用 value 来完成。反正 throw 不会有歧义也没关系。

在 1998 年左右将 throw 添加到该语言时,曾讨论过 throw 语句是否需要表达式。 (替代方案是 throw 没有表达式重新抛出当前异常 object,如 certain other languages。)

我找不到关于这次讨论或最终决议的任何记录——虽然我们知道决议是什么——但在 2 月 19 日会议的 TC39 meeting notes 中提到了它, 1998. 我想限制的目的是让句法 space 保持开放状态,以防有一天决定被改变。