3

According to this, JavaScript will insert a semicolon if:

When the program contains a token that is not allowed by the formal grammar, then a semicolon is inserted if (a) there is a line break at that point, or (b) the unexpected token was a closing brace. (emphasis mine)

The classic example is

return  //  <--- semicolon inserted there
{
   id: 12
};

Which leads me to believe that a free standing { is not valid. Yet the following (pointless) code alerts 2, without error

function foo() {
    var x = 1;
    {
        var y = 2; //yes, I know y has the same scope as x 
    }              //and that this is therefore pointless
    alert(y);
}

Why is the opening brace treated as an invalid token in the first code, which leads JavaScript to insert a semicolon, but the opening brace is not treated as invalid in the second—as evidenced by the fact that there is no error.

Clearly one of my assumptions is wrong, and I was hoping someone could help me understand which.

Adam Rackis
  • 82,527
  • 56
  • 270
  • 393

3 Answers3

5

The return statement problem you mention is not affected by that particular aspect of the semicolon insertion rule. Rather, it's this one:

When, as the program is parsed from left to right, a token is encountered that is allowed by some production of the grammar, but the production is a restricted production and the token would be the first token for a terminal or nonterminal immediately following the annotation ―[no LineTerminator here]‖ within the restricted production (and therefore such a token is called a restricted token), and the restricted token is separated from the previous token by at least one LineTerminator, then a semicolon is automatically inserted before the restricted token.

It so happens that the return statement syntax has one of those "[no LineTerminator here]" quirks.

See section 7.9.1 of the ES 5 spec.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • I apologize humbly for stealing an upvote with my previous, not-really-correct version of this answer. I think the above is correct however. – Pointy Dec 06 '11 at 00:18
  • 1
    As far as I know, `return` by itself is perfectly valid in Javascript, it will just return `undefined`. – Peter Dec 06 '11 at 00:19
  • @Pointy - thank you for digging up that portion of the spec. So I guess you've been using JavaScript for more than a year or two... – Adam Rackis Dec 06 '11 at 05:19
  • @Peter: *"... it will just return `undefined`"* Yes indeed, per [Section 12.9](http://es5.github.com/#x12.9). And in the "distinction without a difference" category, *technically*, there is a difference between an explicit `return;` and execution just reaching the end of the function (implicit return). In the implicit case, the function doesn't return anything -- but the *function call expression* then handles that just like `return;` and `return undefined;` ([Section 13.2.1](http://es5.github.com/#x13.2.1)) – T.J. Crowder Jan 12 '12 at 19:08
2

The rule is like this: if there is a new line, and we have a valid statement so far, then insert a semicolon.

In your first example this is valid:

return;  //  <--- semicolon inserted there
{
   id: 12
};

In the second example, this is invalid:

function foo() {
    var x = 1;
    {;             // *not a valid insertion*
        var y = 2; // yes, I know y has the same scope as x 
    }              // and that this is therefore pointless
    alert(y);
}

EDIT: This answer is not entirely correct! For example:

num = 4 + 5
  + 1;

// returns 10

See comments below:

Peter
  • 3,998
  • 24
  • 33
  • That's not really quite exactly the rule. – Pointy Dec 06 '11 at 00:17
  • @Pointy It's pretty much the rule in a nutshell, can you show me a counter-example please? – Peter Dec 06 '11 at 00:21
  • That is not the rule. Counter-example: `var x = 1 + 2 [newline] + 3 [newline] + 4;` Second counter-example: `var x = document [newline] .getElementById("x1");` – nnnnnn Dec 06 '11 at 01:47
  • @nnnnnn Thanks. Fair enough. So I guess it comes down to knowing which tokens are restricted. I suppose this is the reason semi-colon insertion *should* be avoided. :) – Peter Dec 06 '11 at 02:43
  • I think a reasonable plain-English generalisation is that a semicolon will be inserted for return and throw statements, but otherwise will not be inserted if the next line makes sense as a continuation of the current line. (I wouldn't be surprised if the var statement works the same way, but I can't be bothered to look it up - and I figure since I said "generalisation" it doesn't matter. Arguably return and throw are the two statements most likely to have an incorrect linebreak after them.) – nnnnnn Dec 06 '11 at 02:56
0

You're talking about keywords that are expecting blocks and keywords expecting expressions - return isn't like function or if, that are expecting a block ({ }) - so the parser is going to insert the semi-colon like other keywords not expecting braces.

Dan Heberden
  • 10,990
  • 3
  • 33
  • 29
  • Well a brace is OK if you're returning an object literal. – Pointy Dec 06 '11 at 00:16
  • I'm not saying braces aren't ok, but the parser won't look on the next line for one if it's not expecting it - if you `return {` and have the object keys/values on the next line(s) that's totes cool - or like assignment operators, where `var foo =` can be on line 1, and `{ bar: 'baz' }` can be on the next – Dan Heberden Dec 06 '11 at 00:23