зеркало из https://github.com/mozilla/gecko-dev.git
Bug 883333, part 6 - Further forStatement cleanup. r=Waldo.
--HG-- extra : rebase_source : 214f8fd2cb253e66462d5fd66dd86353acfdc94f
This commit is contained in:
Родитель
15e7bad28b
Коммит
8918d2d7a1
|
@ -220,9 +220,17 @@ class FullParseHandler
|
||||||
return new_<BinaryNode>(PNK_WHILE, JSOP_NOP, pos, cond, body);
|
return new_<BinaryNode>(PNK_WHILE, JSOP_NOP, pos, cond, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode *newForStatement(uint32_t begin) {
|
ParseNode *newForStatement(uint32_t begin, ParseNode *forHead, ParseNode *body,
|
||||||
return new_<BinaryNode>(PNK_FOR, JSOP_NOP, TokenPos::make(begin, begin + 1),
|
unsigned iflags)
|
||||||
(ParseNode *) NULL, (ParseNode *) NULL);
|
{
|
||||||
|
/* A FOR node is binary, left is loop control and right is the body. */
|
||||||
|
JSOp op = forHead->isKind(PNK_FORIN) ? JSOP_ITER : JSOP_NOP;
|
||||||
|
BinaryNode *pn = new_<BinaryNode>(PNK_FOR, op, TokenPos::make(begin, body->pn_pos.end),
|
||||||
|
forHead, body);
|
||||||
|
if (!pn)
|
||||||
|
return null();
|
||||||
|
pn->pn_iflags = iflags;
|
||||||
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode *newForHead(bool isForInOrOf, ParseNode *pn1, ParseNode *pn2, ParseNode *pn3,
|
ParseNode *newForHead(bool isForInOrOf, ParseNode *pn1, ParseNode *pn2, ParseNode *pn3,
|
||||||
|
|
|
@ -3723,9 +3723,9 @@ Parser<ParseHandler>::matchInOrOf(bool *isForOfp)
|
||||||
template <>
|
template <>
|
||||||
bool
|
bool
|
||||||
Parser<FullParseHandler>::isValidForStatementLHS(ParseNode *pn1, JSVersion version,
|
Parser<FullParseHandler>::isValidForStatementLHS(ParseNode *pn1, JSVersion version,
|
||||||
bool forDecl, bool forEach, bool forOf)
|
bool isForDecl, bool isForEach, bool isForOf)
|
||||||
{
|
{
|
||||||
if (forDecl) {
|
if (isForDecl) {
|
||||||
if (pn1->pn_count > 1)
|
if (pn1->pn_count > 1)
|
||||||
return false;
|
return false;
|
||||||
if (pn1->isOp(JSOP_DEFCONST))
|
if (pn1->isOp(JSOP_DEFCONST))
|
||||||
|
@ -3733,7 +3733,7 @@ Parser<FullParseHandler>::isValidForStatementLHS(ParseNode *pn1, JSVersion versi
|
||||||
#if JS_HAS_DESTRUCTURING
|
#if JS_HAS_DESTRUCTURING
|
||||||
// In JS 1.7 only, for (var [K, V] in EXPR) has a special meaning.
|
// In JS 1.7 only, for (var [K, V] in EXPR) has a special meaning.
|
||||||
// Hence all other destructuring decls are banned there.
|
// Hence all other destructuring decls are banned there.
|
||||||
if (version == JSVERSION_1_7 && !forEach && !forOf) {
|
if (version == JSVERSION_1_7 && !isForEach && !isForOf) {
|
||||||
ParseNode *lhs = pn1->pn_head;
|
ParseNode *lhs = pn1->pn_head;
|
||||||
if (lhs->isKind(PNK_ASSIGN))
|
if (lhs->isKind(PNK_ASSIGN))
|
||||||
lhs = lhs->pn_left;
|
lhs = lhs->pn_left;
|
||||||
|
@ -3759,7 +3759,7 @@ Parser<FullParseHandler>::isValidForStatementLHS(ParseNode *pn1, JSVersion versi
|
||||||
case PNK_OBJECT:
|
case PNK_OBJECT:
|
||||||
// In JS 1.7 only, for ([K, V] in EXPR) has a special meaning.
|
// In JS 1.7 only, for ([K, V] in EXPR) has a special meaning.
|
||||||
// Hence all other destructuring left-hand sides are banned there.
|
// Hence all other destructuring left-hand sides are banned there.
|
||||||
if (version == JSVERSION_1_7 && !forEach && !forOf)
|
if (version == JSVERSION_1_7 && !isForEach && !isForOf)
|
||||||
return pn1->isKind(PNK_ARRAY) && pn1->pn_count == 2;
|
return pn1->isKind(PNK_ARRAY) && pn1->pn_count == 2;
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
@ -3791,16 +3791,15 @@ Parser<FullParseHandler>::forStatement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenPos lp_pos = pos();
|
|
||||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
|
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* True if we have 'for (var/let/const ...)', except in the oddball case
|
* True if we have 'for (var/let/const ...)', except in the oddball case
|
||||||
* where 'let' begins a let-expression in 'for (let (...) ...)'.
|
* where 'let' begins a let-expression in 'for (let (...) ...)'.
|
||||||
*/
|
*/
|
||||||
bool forDecl = false;
|
bool isForDecl = false;
|
||||||
|
|
||||||
/* Non-null when forDecl is true for a 'for (let ...)' statement. */
|
/* Non-null when isForDecl is true for a 'for (let ...)' statement. */
|
||||||
RootedStaticBlockObject blockObj(context);
|
RootedStaticBlockObject blockObj(context);
|
||||||
|
|
||||||
/* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
|
/* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
|
||||||
|
@ -3826,7 +3825,7 @@ Parser<FullParseHandler>::forStatement()
|
||||||
*/
|
*/
|
||||||
pc->parsingForInit = true;
|
pc->parsingForInit = true;
|
||||||
if (tt == TOK_VAR || tt == TOK_CONST) {
|
if (tt == TOK_VAR || tt == TOK_CONST) {
|
||||||
forDecl = true;
|
isForDecl = true;
|
||||||
tokenStream.consumeKnownToken(tt);
|
tokenStream.consumeKnownToken(tt);
|
||||||
pn1 = variables(tt == TOK_VAR ? PNK_VAR : PNK_CONST);
|
pn1 = variables(tt == TOK_VAR ? PNK_VAR : PNK_CONST);
|
||||||
}
|
}
|
||||||
|
@ -3837,7 +3836,7 @@ Parser<FullParseHandler>::forStatement()
|
||||||
if (tokenStream.peekToken() == TOK_LP) {
|
if (tokenStream.peekToken() == TOK_LP) {
|
||||||
pn1 = letBlock(LetExpresion);
|
pn1 = letBlock(LetExpresion);
|
||||||
} else {
|
} else {
|
||||||
forDecl = true;
|
isForDecl = true;
|
||||||
blockObj = StaticBlockObject::create(context);
|
blockObj = StaticBlockObject::create(context);
|
||||||
if (!blockObj)
|
if (!blockObj)
|
||||||
return null();
|
return null();
|
||||||
|
@ -3854,15 +3853,21 @@ Parser<FullParseHandler>::forStatement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT_IF(forDecl, pn1->isArity(PN_LIST));
|
JS_ASSERT_IF(isForDecl, pn1->isArity(PN_LIST));
|
||||||
JS_ASSERT(!!blockObj == (forDecl && pn1->isOp(JSOP_NOP)));
|
JS_ASSERT(!!blockObj == (isForDecl && pn1->isOp(JSOP_NOP)));
|
||||||
|
|
||||||
ParseNode *pn = handler.newForStatement(begin);
|
// The form 'for (let <vars>; <expr2>; <expr3>) <stmt>' generates an
|
||||||
if (!pn)
|
// implicit block even if stmt is not a BlockStatement.
|
||||||
return null();
|
// If the loop has that exact form, then:
|
||||||
|
// - forLetImpliedBlock is the node for the implicit block scope.
|
||||||
|
// - forLetDecl is the node for the decl 'let <vars>'.
|
||||||
|
// Otherwise both are null.
|
||||||
|
ParseNode *forLetImpliedBlock = NULL;
|
||||||
|
ParseNode *forLetDecl = NULL;
|
||||||
|
|
||||||
/* If non-null, the parent that should be returned instead of pn. */
|
// If non-null, the node for the decl 'var v = expr1' in the weirdo form
|
||||||
ParseNode *forParent = NULL;
|
// 'for (var v = expr1 in expr2) stmt'.
|
||||||
|
ParseNode *hoistedVar = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can be sure that it's a for/in loop if there's still an 'in'
|
* We can be sure that it's a for/in loop if there's still an 'in'
|
||||||
|
@ -3871,9 +3876,9 @@ Parser<FullParseHandler>::forStatement()
|
||||||
* pc->parsingForInit.
|
* pc->parsingForInit.
|
||||||
*/
|
*/
|
||||||
StmtInfoPC letStmt(context); /* used if blockObj != NULL. */
|
StmtInfoPC letStmt(context); /* used if blockObj != NULL. */
|
||||||
ParseNode *pn2, *pn3; /* forHead->pn_kid1 and pn_kid2. */
|
ParseNode *pn2, *pn3; /* forHead->pn_kid2 and pn_kid3. */
|
||||||
bool forOf;
|
bool isForOf;
|
||||||
bool isForInOrOf = pn1 && matchInOrOf(&forOf);
|
bool isForInOrOf = pn1 && matchInOrOf(&isForOf);
|
||||||
if (isForInOrOf) {
|
if (isForInOrOf) {
|
||||||
/*
|
/*
|
||||||
* Parse the rest of the for/in or for/of head.
|
* Parse the rest of the for/in or for/of head.
|
||||||
|
@ -3886,14 +3891,14 @@ Parser<FullParseHandler>::forStatement()
|
||||||
forStmt.type = STMT_FOR_IN_LOOP;
|
forStmt.type = STMT_FOR_IN_LOOP;
|
||||||
|
|
||||||
/* Set iflags and rule out invalid combinations. */
|
/* Set iflags and rule out invalid combinations. */
|
||||||
if (forOf && isForEach) {
|
if (isForOf && isForEach) {
|
||||||
report(ParseError, false, null(), JSMSG_BAD_FOR_EACH_LOOP);
|
report(ParseError, false, null(), JSMSG_BAD_FOR_EACH_LOOP);
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
iflags |= (forOf ? JSITER_FOR_OF : JSITER_ENUMERATE);
|
iflags |= (isForOf ? JSITER_FOR_OF : JSITER_ENUMERATE);
|
||||||
|
|
||||||
/* Check that the left side of the 'in' or 'of' is valid. */
|
/* Check that the left side of the 'in' or 'of' is valid. */
|
||||||
if (!isValidForStatementLHS(pn1, versionNumber(), forDecl, isForEach, forOf)) {
|
if (!isValidForStatementLHS(pn1, versionNumber(), isForDecl, isForEach, isForOf)) {
|
||||||
report(ParseError, false, pn1, JSMSG_BAD_FOR_LEFTSIDE);
|
report(ParseError, false, pn1, JSMSG_BAD_FOR_LEFTSIDE);
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
@ -3904,7 +3909,7 @@ Parser<FullParseHandler>::forStatement()
|
||||||
* any, else NULL. Note that the "declaration with initializer" case
|
* any, else NULL. Note that the "declaration with initializer" case
|
||||||
* rewrites the loop-head, moving the decl and setting pn1 to NULL.
|
* rewrites the loop-head, moving the decl and setting pn1 to NULL.
|
||||||
*/
|
*/
|
||||||
if (forDecl) {
|
if (isForDecl) {
|
||||||
pn2 = pn1->pn_head;
|
pn2 = pn1->pn_head;
|
||||||
if ((pn2->isKind(PNK_NAME) && pn2->maybeExpr())
|
if ((pn2->isKind(PNK_NAME) && pn2->maybeExpr())
|
||||||
#if JS_HAS_DESTRUCTURING
|
#if JS_HAS_DESTRUCTURING
|
||||||
|
@ -3926,9 +3931,7 @@ Parser<FullParseHandler>::forStatement()
|
||||||
}
|
}
|
||||||
#endif /* JS_HAS_BLOCK_SCOPE */
|
#endif /* JS_HAS_BLOCK_SCOPE */
|
||||||
|
|
||||||
ParseNode *pnseq = handler.newList(PNK_SEQ, pn1);
|
hoistedVar = pn1;
|
||||||
if (!pnseq)
|
|
||||||
return null();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All of 'var x = i' is hoisted above 'for (x in o)'.
|
* All of 'var x = i' is hoisted above 'for (x in o)'.
|
||||||
|
@ -3947,9 +3950,6 @@ Parser<FullParseHandler>::forStatement()
|
||||||
pn2->isKind(PNK_NAME));
|
pn2->isKind(PNK_NAME));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
pnseq->pn_pos.begin = pn->pn_pos.begin;
|
|
||||||
pnseq->append(pn);
|
|
||||||
forParent = pnseq;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Not a declaration. */
|
/* Not a declaration. */
|
||||||
|
@ -3981,7 +3981,7 @@ Parser<FullParseHandler>::forStatement()
|
||||||
pn1 = block;
|
pn1 = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forDecl) {
|
if (isForDecl) {
|
||||||
/*
|
/*
|
||||||
* pn2 is part of a declaration. Make a copy that can be passed to
|
* pn2 is part of a declaration. Make a copy that can be passed to
|
||||||
* EmitAssignment. Take care to do this after PushLetScope.
|
* EmitAssignment. Take care to do this after PushLetScope.
|
||||||
|
@ -4009,7 +4009,7 @@ Parser<FullParseHandler>::forStatement()
|
||||||
* Destructuring for-in requires [key, value] enumeration
|
* Destructuring for-in requires [key, value] enumeration
|
||||||
* in JS1.7.
|
* in JS1.7.
|
||||||
*/
|
*/
|
||||||
if (!isForEach && !forOf)
|
if (!isForEach && !isForOf)
|
||||||
iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
|
iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -4019,7 +4019,7 @@ Parser<FullParseHandler>::forStatement()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isForEach) {
|
if (isForEach) {
|
||||||
report(ParseError, false, pn, JSMSG_BAD_FOR_EACH_LOOP);
|
reportWithOffset(ParseError, false, begin, JSMSG_BAD_FOR_EACH_LOOP);
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4028,18 +4028,13 @@ Parser<FullParseHandler>::forStatement()
|
||||||
* Desugar 'for (let A; B; C) D' into 'let (A) { for (; B; C) D }'
|
* Desugar 'for (let A; B; C) D' into 'let (A) { for (; B; C) D }'
|
||||||
* to induce the correct scoping for A.
|
* to induce the correct scoping for A.
|
||||||
*/
|
*/
|
||||||
ParseNode *block = pushLetScope(blockObj, &letStmt);
|
forLetImpliedBlock = pushLetScope(blockObj, &letStmt);
|
||||||
if (!block)
|
if (!forLetImpliedBlock)
|
||||||
return null();
|
return null();
|
||||||
letStmt.isForLetBlock = true;
|
letStmt.isForLetBlock = true;
|
||||||
|
|
||||||
ParseNode *let = handler.newBinary(PNK_LET, pn1, block);
|
forLetDecl = pn1;
|
||||||
if (!let)
|
|
||||||
return null();
|
|
||||||
|
|
||||||
pn1 = NULL;
|
pn1 = NULL;
|
||||||
block->pn_expr = pn;
|
|
||||||
forParent = let;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse the loop condition or null into pn2. */
|
/* Parse the loop condition or null into pn2. */
|
||||||
|
@ -4063,36 +4058,46 @@ Parser<FullParseHandler>::forStatement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenPos headPos = TokenPos::make(lp_pos.begin, pos().end);
|
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
|
||||||
|
|
||||||
|
TokenPos headPos = TokenPos::make(begin, pos().end);
|
||||||
ParseNode *forHead = handler.newForHead(isForInOrOf, pn1, pn2, pn3, headPos);
|
ParseNode *forHead = handler.newForHead(isForInOrOf, pn1, pn2, pn3, headPos);
|
||||||
if (!forHead)
|
if (!forHead)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
|
|
||||||
|
|
||||||
/* Parse the loop body. */
|
/* Parse the loop body. */
|
||||||
ParseNode *body = statement();
|
ParseNode *body = statement();
|
||||||
if (!body)
|
if (!body)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
/* A FOR node is binary, left is loop control and right is the body. */
|
|
||||||
pn->setOp(isForInOrOf ? JSOP_ITER : JSOP_NOP);
|
|
||||||
pn->pn_left = forHead;
|
|
||||||
pn->pn_right = body;
|
|
||||||
pn->pn_iflags = iflags;
|
|
||||||
pn->pn_pos.end = body->pn_pos.end;
|
|
||||||
|
|
||||||
if (forParent) {
|
|
||||||
forParent->pn_pos.begin = pn->pn_pos.begin;
|
|
||||||
forParent->pn_pos.end = pn->pn_pos.end;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if JS_HAS_BLOCK_SCOPE
|
#if JS_HAS_BLOCK_SCOPE
|
||||||
if (blockObj)
|
if (blockObj)
|
||||||
PopStatementPC(context, pc);
|
PopStatementPC(context, pc);
|
||||||
#endif
|
#endif
|
||||||
PopStatementPC(context, pc);
|
PopStatementPC(context, pc);
|
||||||
return forParent ? forParent : pn;
|
|
||||||
|
ParseNode *forLoop = handler.newForStatement(begin, forHead, body, iflags);
|
||||||
|
if (!forLoop)
|
||||||
|
return null();
|
||||||
|
|
||||||
|
if (hoistedVar) {
|
||||||
|
ParseNode *pnseq = handler.newList(PNK_SEQ, hoistedVar);
|
||||||
|
if (!pnseq)
|
||||||
|
return null();
|
||||||
|
pnseq->pn_pos = forLoop->pn_pos;
|
||||||
|
pnseq->append(forLoop);
|
||||||
|
return pnseq;
|
||||||
|
}
|
||||||
|
if (forLetImpliedBlock) {
|
||||||
|
forLetImpliedBlock->pn_expr = forLoop;
|
||||||
|
forLetImpliedBlock->pn_pos = forLoop->pn_pos;
|
||||||
|
ParseNode *let = handler.newBinary(PNK_LET, forLetDecl, forLetImpliedBlock);
|
||||||
|
if (!let)
|
||||||
|
return null();
|
||||||
|
let->pn_pos = forLoop->pn_pos;
|
||||||
|
return let;
|
||||||
|
}
|
||||||
|
return forLoop;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -4119,7 +4124,7 @@ Parser<SyntaxParseHandler>::forStatement()
|
||||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
|
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
|
||||||
|
|
||||||
/* True if we have 'for (var ...)'. */
|
/* True if we have 'for (var ...)'. */
|
||||||
bool forDecl = false;
|
bool isForDecl = false;
|
||||||
bool simpleForDecl = true;
|
bool simpleForDecl = true;
|
||||||
|
|
||||||
/* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
|
/* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
|
||||||
|
@ -4133,7 +4138,7 @@ Parser<SyntaxParseHandler>::forStatement()
|
||||||
/* Set lhsNode to a var list or an initializing expression. */
|
/* Set lhsNode to a var list or an initializing expression. */
|
||||||
pc->parsingForInit = true;
|
pc->parsingForInit = true;
|
||||||
if (tt == TOK_VAR) {
|
if (tt == TOK_VAR) {
|
||||||
forDecl = true;
|
isForDecl = true;
|
||||||
tokenStream.consumeKnownToken(tt);
|
tokenStream.consumeKnownToken(tt);
|
||||||
lhsNode = variables(tt == TOK_VAR ? PNK_VAR : PNK_CONST, &simpleForDecl);
|
lhsNode = variables(tt == TOK_VAR ? PNK_VAR : PNK_CONST, &simpleForDecl);
|
||||||
}
|
}
|
||||||
|
@ -4158,13 +4163,13 @@ Parser<SyntaxParseHandler>::forStatement()
|
||||||
* as we've excluded 'in' from being parsed in RelExpr by setting
|
* as we've excluded 'in' from being parsed in RelExpr by setting
|
||||||
* pc->parsingForInit.
|
* pc->parsingForInit.
|
||||||
*/
|
*/
|
||||||
bool forOf;
|
bool isForOf;
|
||||||
if (lhsNode && matchInOrOf(&forOf)) {
|
if (lhsNode && matchInOrOf(&isForOf)) {
|
||||||
/* Parse the rest of the for/in or for/of head. */
|
/* Parse the rest of the for/in or for/of head. */
|
||||||
forStmt.type = STMT_FOR_IN_LOOP;
|
forStmt.type = STMT_FOR_IN_LOOP;
|
||||||
|
|
||||||
/* Check that the left side of the 'in' or 'of' is valid. */
|
/* Check that the left side of the 'in' or 'of' is valid. */
|
||||||
if (!forDecl &&
|
if (!isForDecl &&
|
||||||
lhsNode != SyntaxParseHandler::NodeName &&
|
lhsNode != SyntaxParseHandler::NodeName &&
|
||||||
lhsNode != SyntaxParseHandler::NodeGetProp &&
|
lhsNode != SyntaxParseHandler::NodeGetProp &&
|
||||||
lhsNode != SyntaxParseHandler::NodeLValue)
|
lhsNode != SyntaxParseHandler::NodeLValue)
|
||||||
|
@ -4178,7 +4183,7 @@ Parser<SyntaxParseHandler>::forStatement()
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!forDecl && !setAssignmentLhsOps(lhsNode, JSOP_NOP))
|
if (!isForDecl && !setAssignmentLhsOps(lhsNode, JSOP_NOP))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
if (!expr())
|
if (!expr())
|
||||||
|
@ -5871,12 +5876,12 @@ Parser<FullParseHandler>::comprehensionTail(ParseNode *kid, unsigned blockid, bo
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool forOf;
|
bool isForOf;
|
||||||
if (!matchInOrOf(&forOf)) {
|
if (!matchInOrOf(&isForOf)) {
|
||||||
report(ParseError, false, null(), JSMSG_IN_AFTER_FOR_NAME);
|
report(ParseError, false, null(), JSMSG_IN_AFTER_FOR_NAME);
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
if (forOf) {
|
if (isForOf) {
|
||||||
if (pn2->pn_iflags != JSITER_ENUMERATE) {
|
if (pn2->pn_iflags != JSITER_ENUMERATE) {
|
||||||
JS_ASSERT(pn2->pn_iflags == (JSITER_FOREACH | JSITER_ENUMERATE));
|
JS_ASSERT(pn2->pn_iflags == (JSITER_FOREACH | JSITER_ENUMERATE));
|
||||||
report(ParseError, false, null(), JSMSG_BAD_FOR_EACH_LOOP);
|
report(ParseError, false, null(), JSMSG_BAD_FOR_EACH_LOOP);
|
||||||
|
@ -5909,7 +5914,7 @@ Parser<FullParseHandler>::comprehensionTail(ParseNode *kid, unsigned blockid, bo
|
||||||
|
|
||||||
if (versionNumber() == JSVERSION_1_7 &&
|
if (versionNumber() == JSVERSION_1_7 &&
|
||||||
!(pn2->pn_iflags & JSITER_FOREACH) &&
|
!(pn2->pn_iflags & JSITER_FOREACH) &&
|
||||||
!forOf)
|
!isForOf)
|
||||||
{
|
{
|
||||||
/* Destructuring requires [key, value] enumeration in JS1.7. */
|
/* Destructuring requires [key, value] enumeration in JS1.7. */
|
||||||
if (!pn3->isKind(PNK_ARRAY) || pn3->pn_count != 2) {
|
if (!pn3->isKind(PNK_ARRAY) || pn3->pn_count != 2) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче