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:
++
--
continue
[no LineTerminator here] LabelIdentifier[?Yield];
break
[no LineTerminator here] LabelIdentifier[?Yield];
return
[no LineTerminator here] Expression ;
return
[no LineTerminator here] Expression[In, ?Yield];
throw
[no LineTerminator here] Expression[In, ?Yield];
=>
ConciseBody[?In]
yield
[no LineTerminator here] *
AssignmentExpression[?In, Yield]
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, e.g. 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With