为什么 "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[Yield] : LeftHandSideExpression[?Yield] [这里没有LineTerminator]
++
- PostfixExpression[Yield] : LeftHandSideExpression[?Yield] [这里没有LineTerminator]
--
- ContinueStatement[Yield] :
continue
[no LineTerminator 这里] LabelIdentifier[?Yield] ;
- BreakStatement[Yield] :
break
[no LineTerminator 这里] LabelIdentifier[?Yield] ;
- ReturnStatement[Yield]:
return
[noLineTerminator 这里] 表达式 ;
- ReturnStatement[Yield]:
return
[noLineTerminator here] Expression[In, ?Yield] ;
- ThrowStatement[Yield]:
throw
[noLineTerminator here] Expression[In, ?Yield] ;
- ArrowFunction[In, Yield] : ArrowParameters[?Yield] [这里没有LineTerminator]
=>
ConciseBody[?在]
- YieldExpression[In]:
yield
[无LineTerminator这里]*
AssignmentExpression[?In, Yield]
- YieldExpression[In]:
yield
[无LineTerminator 这里] AssignmentExpression[?In, Yield]
在这些作品中,我理解对其中大部分进行限制的选择。 PostfixExpression 的产生式被限制以防止与 PrefixExpression 的解析歧义。 ContinueStatement、BreakStatement 和 ReturnStatement 有限制产生式,因为有相应的产生式 break
并且 continue
不带标签并且 return
不带表达式。我不能说我对箭头函数或 yield 表达式了解得足够多以知道为什么它们受到限制,但我认为这是为了防止某种类似的解析歧义。
我不明白的产生式是ThrowExpression。据我所知,使用 throw
不会像使用 break
、return
和 continue
时那样出现解析歧义:毕竟,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 ¶ value
和 throw ¶ value
都是禁止的,如果你想用 value
来完成。反正 throw
不会有歧义也没关系。
在 1998 年左右将 throw
添加到该语言时,曾讨论过 throw 语句是否需要表达式。 (替代方案是 throw
没有表达式重新抛出当前异常 object,如 certain other languages。)
我找不到关于这次讨论或最终决议的任何记录——虽然我们知道决议是什么——但在 2 月 19 日会议的 TC39 meeting notes 中提到了它, 1998. 我想限制的目的是让句法 space 保持开放状态,以防有一天决定被改变。
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[Yield] : LeftHandSideExpression[?Yield] [这里没有LineTerminator]
++
- PostfixExpression[Yield] : LeftHandSideExpression[?Yield] [这里没有LineTerminator]
--
- ContinueStatement[Yield] :
continue
[no LineTerminator 这里] LabelIdentifier[?Yield];
- BreakStatement[Yield] :
break
[no LineTerminator 这里] LabelIdentifier[?Yield];
- ReturnStatement[Yield]:
return
[noLineTerminator 这里] 表达式;
- ReturnStatement[Yield]:
return
[noLineTerminator here] Expression[In, ?Yield];
- ThrowStatement[Yield]:
throw
[noLineTerminator here] Expression[In, ?Yield];
- ArrowFunction[In, Yield] : ArrowParameters[?Yield] [这里没有LineTerminator]
=>
ConciseBody[?在] - YieldExpression[In]:
yield
[无LineTerminator这里]*
AssignmentExpression[?In, Yield] - YieldExpression[In]:
yield
[无LineTerminator 这里] AssignmentExpression[?In, Yield]
在这些作品中,我理解对其中大部分进行限制的选择。 PostfixExpression 的产生式被限制以防止与 PrefixExpression 的解析歧义。 ContinueStatement、BreakStatement 和 ReturnStatement 有限制产生式,因为有相应的产生式 break
并且 continue
不带标签并且 return
不带表达式。我不能说我对箭头函数或 yield 表达式了解得足够多以知道为什么它们受到限制,但我认为这是为了防止某种类似的解析歧义。
我不明白的产生式是ThrowExpression。据我所知,使用 throw
不会像使用 break
、return
和 continue
时那样出现解析歧义:毕竟,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 ¶ value
和 throw ¶ value
都是禁止的,如果你想用 value
来完成。反正 throw
不会有歧义也没关系。
在 1998 年左右将 throw
添加到该语言时,曾讨论过 throw 语句是否需要表达式。 (替代方案是 throw
没有表达式重新抛出当前异常 object,如 certain other languages。)
我找不到关于这次讨论或最终决议的任何记录——虽然我们知道决议是什么——但在 2 月 19 日会议的 TC39 meeting notes 中提到了它, 1998. 我想限制的目的是让句法 space 保持开放状态,以防有一天决定被改变。