简体   繁体   中英

Why is “throw” a restricted production for automatic semicolon insertion?

Part of JavaScript's automatic semicolon insertion algorithm is so-called "restricted productions". These are syntactical forms which forbid a newline character from occurring at a certain point. To quote the ECMAScript 2015 specification:

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.

There are 10 restricted productions in the ECMAScript 2015 specification:

  • PostfixExpression [Yield] : LeftHandSideExpression [?Yield] [no LineTerminator here] ++
  • PostfixExpression [Yield] : LeftHandSideExpression [?Yield] [no LineTerminator here] --
  • ContinueStatement [Yield] : continue [no LineTerminator here] LabelIdentifier [?Yield] ;
  • BreakStatement [Yield] : break [no LineTerminator here] LabelIdentifier [?Yield] ;
  • ReturnStatement [Yield] : return [no LineTerminator here] Expression ;
  • ReturnStatement [Yield] : return [no LineTerminator here] Expression [In, ?Yield] ;
  • ThrowStatement [Yield] : throw [no LineTerminator here] Expression [In, ?Yield] ;
  • ArrowFunction [In, Yield] : ArrowParameters [?Yield] [no LineTerminator here] => ConciseBody [?In]
  • YieldExpression [In] : yield [no LineTerminator here] * AssignmentExpression [?In, Yield]
  • YieldExpression [In] : yield [no LineTerminator here] AssignmentExpression [?In, Yield]

Of these productions, I understand the choice to make most of them restricted. The production for PostfixExpression is restricted to prevent parsing ambiguity with PrefixExpression . ContinueStatement , BreakStatement , and ReturnStatement have restricted productions because there are corresponding productions where break and continue do not take labels and return does not take an expression. I can't say that I know enough about arrow functions or yield expressions to know why they are restricted, but I assume it is to prevent some sort of similar parsing ambiguity.

The production which I don't understand is ThrowExpression . As far as I can tell, there is no parsing ambiguity involved in using throw like there is when using break , return , and continue : after all, throw; is not valid JavaScript. I thought that it might be for historical reasons, but as far as I can tell throw; has never been allowed in any JavaScript specification.

The practical consequence of this is that much like with return , you can't put the expression being thrown on the next line, eg this is wrong:

throw
new Error("some error");

However, unlike return , this doesn't have different behavior than putting the new Error() on the same line. It's just a syntax error: Chrome reports it as

Uncaught SyntaxError: Illegal newline after throw

Is the production for ThrowExpression restricted just to maintain consistency with similar contstructs? Or is there some ambiguity I'm not seeing?

When throw was added to the language in 1998 or so, there was a discussion about whether the throw statement required an expression or not. (The alternative would be that a throw without an expression rethrows the current exception object, as in certain other languages .)

I can't find any record of this discussion, or of the final resolution -- although we know what the resolution was -- but it is mentioned in the TC39 meeting notes for the meeting of February 19, 1998. I suppose that the intent of the restriction was to leave the syntactic space open in case someday the decision were changed.

We can only guess here why the language authors decided to make it so, but I'd say it's for consistency with return . Both return ¶ value and throw ¶ value are forbidden if you want to complete with the value . That there would be no ambiguity for throw anyway doesn't matter.

I think adeneo's comment is on the right track: like return , the operand to throw is typically a valid expression on its own. The problem with return \\n "valid on its own"; is one of the most common examples of ASI problems, so restricting return and any other statements taking a value like that is a reasonable safeguard.

Looking at the list, most of those are unary operators (or look just like one). They all follow the same general form, except for arrow functions. That form is a cause of ASI errors, so restricting the whole category is more predictable than just return .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM