Bug 696813 - Simplify Parser::forStatement (r=jorendorff)

--HG--
extra : rebase_source : 9e5d9eebffee46d35a55e869a45b8ec5db5877e6
This commit is contained in:
Luke Wagner 2011-10-21 10:54:33 -07:00
parent 1ed9041d38
commit 01f92afc5d

View File

@ -3076,60 +3076,70 @@ Parser::forStatement()
} }
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
TokenKind tt = tokenStream.peekToken(TSF_OPERAND);
#if JS_HAS_BLOCK_SCOPE #ifdef JS_HAS_BLOCK_SCOPE
bool let = false; bool let = false;
#endif #endif
ParseNode *pn1; /*
if (tt == TOK_SEMI) { * True if we have 'for (var/let/const ...)', except in the oddball case
if (pn->pn_iflags & JSITER_FOREACH) { * where 'let' begins a let-expression in 'for (let (...) ...)'.
reportErrorNumber(pn, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP); */
return NULL; bool forDecl = false;
}
/* No initializer -- set first kid of left sub-node to null. */ /* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
pn1 = NULL; ParseNode *pn1;
} else {
/* {
* Set pn1 to a var list or an initializing expression. TokenKind tt = tokenStream.peekToken(TSF_OPERAND);
* if (tt == TOK_SEMI) {
* Set the TCF_IN_FOR_INIT flag during parsing of the first clause if (pn->pn_iflags & JSITER_FOREACH) {
* of the for statement. This flag will be used by the RelExpr reportErrorNumber(pn, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP);
* production; if it is set, then the 'in' keyword will not be return NULL;
* recognized as an operator, leaving it available to be parsed as
* part of a for/in loop.
*
* A side effect of this restriction is that (unparenthesized)
* expressions involving an 'in' operator are illegal in the init
* clause of an ordinary for loop.
*/
tc->flags |= TCF_IN_FOR_INIT;
if (tt == TOK_VAR) {
(void) tokenStream.getToken();
pn1 = variables(false);
#if JS_HAS_BLOCK_SCOPE
} else if (tt == TOK_LET) {
let = true;
(void) tokenStream.getToken();
if (tokenStream.peekToken() == TOK_LP) {
pn1 = letBlock(JS_FALSE);
tt = TOK_LEXICALSCOPE;
} else {
pnlet = PushLexicalScope(context, &tokenStream, tc, &blockInfo);
if (!pnlet)
return NULL;
blockInfo.flags |= SIF_FOR_BLOCK;
pn1 = variables(false);
} }
#endif
pn1 = NULL;
} else { } else {
pn1 = expr(); /*
* Set pn1 to a var list or an initializing expression.
*
* Set the TCF_IN_FOR_INIT flag during parsing of the first clause
* of the for statement. This flag will be used by the RelExpr
* production; if it is set, then the 'in' keyword will not be
* recognized as an operator, leaving it available to be parsed as
* part of a for/in loop.
*
* A side effect of this restriction is that (unparenthesized)
* expressions involving an 'in' operator are illegal in the init
* clause of an ordinary for loop.
*/
tc->flags |= TCF_IN_FOR_INIT;
if (tt == TOK_VAR) {
forDecl = true;
(void) tokenStream.getToken();
pn1 = variables(false);
#if JS_HAS_BLOCK_SCOPE
} else if (tt == TOK_LET) {
let = true;
(void) tokenStream.getToken();
if (tokenStream.peekToken() == TOK_LP) {
pn1 = letBlock(JS_FALSE);
} else {
forDecl = true;
pnlet = PushLexicalScope(context, &tokenStream, tc, &blockInfo);
if (!pnlet)
return NULL;
blockInfo.flags |= SIF_FOR_BLOCK;
pn1 = variables(false);
}
#endif
} else {
pn1 = expr();
}
tc->flags &= ~TCF_IN_FOR_INIT;
if (!pn1)
return NULL;
} }
tc->flags &= ~TCF_IN_FOR_INIT;
if (!pn1)
return NULL;
} }
/* /*
@ -3154,8 +3164,7 @@ Parser::forStatement()
stmtInfo.type = STMT_FOR_IN_LOOP; stmtInfo.type = STMT_FOR_IN_LOOP;
/* Check that the left side of the 'in' is valid. */ /* Check that the left side of the 'in' is valid. */
JS_ASSERT(!TokenKindIsDecl(tt) || pn1->isKind(tt)); if (forDecl
if (TokenKindIsDecl(tt)
? (pn1->pn_count > 1 || pn1->isOp(JSOP_DEFCONST) ? (pn1->pn_count > 1 || pn1->isOp(JSOP_DEFCONST)
#if JS_HAS_DESTRUCTURING #if JS_HAS_DESTRUCTURING
|| (versionNumber() == JSVERSION_1_7 && || (versionNumber() == JSVERSION_1_7 &&
@ -3196,7 +3205,7 @@ Parser::forStatement()
*/ */
pn2 = NULL; pn2 = NULL;
uintN dflag = PND_ASSIGNED; uintN dflag = PND_ASSIGNED;
if (TokenKindIsDecl(tt)) { if (forDecl) {
/* Tell EmitVariables that pn1 is part of a for/in. */ /* Tell EmitVariables that pn1 is part of a for/in. */
pn1->pn_xflags |= PNX_FORINVAR; pn1->pn_xflags |= PNX_FORINVAR;
@ -3211,10 +3220,10 @@ Parser::forStatement()
* *
* Rewrite 'for (<decl> x = i in o)' where <decl> is 'var' or * Rewrite 'for (<decl> x = i in o)' where <decl> is 'var' or
* 'const' to hoist the initializer or the entire decl out of * 'const' to hoist the initializer or the entire decl out of
* the loop head. TOK_VAR is the type for both 'var' and 'const'. * the loop head.
*/ */
#if JS_HAS_BLOCK_SCOPE #if JS_HAS_BLOCK_SCOPE
if (tt == TOK_LET) { if (let) {
reportErrorNumber(pn2, JSREPORT_ERROR, JSMSG_INVALID_FOR_IN_INIT); reportErrorNumber(pn2, JSREPORT_ERROR, JSMSG_INVALID_FOR_IN_INIT);
return NULL; return NULL;
} }
@ -3322,7 +3331,7 @@ Parser::forStatement()
/* Parse the loop condition or null into pn2. */ /* Parse the loop condition or null into pn2. */
MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT); MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
tt = tokenStream.peekToken(TSF_OPERAND); TokenKind tt = tokenStream.peekToken(TSF_OPERAND);
if (tt == TOK_SEMI) { if (tt == TOK_SEMI) {
pn2 = NULL; pn2 = NULL;
} else { } else {