Bug 1130811 - Split out of PNK_LET (used for let declarations, deprecated let blocks, and deprecated let expressions) additional PNK_LETBLOCK and PNK_LETEXPR kinds. r=shu

--HG--
extra : rebase_source : 0d628316044cafddf2b0ee890219c02b879dffc4
This commit is contained in:
Jeff Walden 2015-02-09 17:12:11 -08:00
parent b09b675f9f
commit 3e0f48699f
7 changed files with 87 additions and 42 deletions

View File

@ -7202,12 +7202,14 @@ frontend::EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
ok = EmitLexicalScope(cx, bce, pn);
break;
case PNK_LET:
case PNK_LETBLOCK:
case PNK_LETEXPR:
ok = EmitLet(cx, bce, pn);
break;
case PNK_CONST:
MOZ_ASSERT_IF(pn->isKind(PNK_CONST), !pn->isArity(PN_BINARY));
ok = pn->isArity(PN_BINARY)
? EmitLet(cx, bce, pn)
: EmitVariables(cx, bce, pn, InitializeVars);
case PNK_LET:
ok = EmitVariables(cx, bce, pn, InitializeVars);
break;
case PNK_IMPORT:

View File

@ -540,6 +540,22 @@ class FullParseHandler
block->pn_expr = body;
}
ParseNode *newLetExpression(ParseNode *vars, ParseNode *block, const TokenPos &pos) {
ParseNode *letExpr = newBinary(PNK_LETEXPR, vars, block);
if (!letExpr)
return nullptr;
letExpr->pn_pos = pos;
return letExpr;
}
ParseNode *newLetBlock(ParseNode *vars, ParseNode *block, const TokenPos &pos) {
ParseNode *letBlock = newBinary(PNK_LETBLOCK, vars, block);
if (!letBlock)
return nullptr;
letBlock->pn_pos = pos;
return letBlock;
}
ParseNode *newAssignment(ParseNodeKind kind, ParseNode *lhs, ParseNode *rhs,
ParseContext<FullParseHandler> *pc, JSOp op)
{

View File

@ -131,6 +131,8 @@ class UpvarCookie
F(ARRAYPUSH) \
F(LEXICALSCOPE) \
F(LET) \
F(LETBLOCK) \
F(LETEXPR) \
F(IMPORT) \
F(IMPORT_SPEC_LIST) \
F(IMPORT_SPEC) \

View File

@ -3622,7 +3622,7 @@ Parser<SyntaxParseHandler>::pushLetScope(HandleStaticBlockObject blockObj, StmtI
*/
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::letBlock(LetContext letContext)
Parser<ParseHandler>::deprecatedLetBlockOrExpression(LetContext letContext)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LET));
@ -3645,11 +3645,6 @@ Parser<ParseHandler>::letBlock(LetContext letContext)
if (!block)
return null();
Node pnlet = handler.newBinary(PNK_LET, vars, block);
if (!pnlet)
return null();
handler.setBeginPosition(pnlet, begin);
bool needExprStmt = false;
if (letContext == LetStatement) {
bool matched;
@ -3672,16 +3667,16 @@ Parser<ParseHandler>::letBlock(LetContext letContext)
*
* See bug 569464.
*/
if (!report(ParseStrictError, pc->sc->strict, pnlet,
JSMSG_STRICT_CODE_LET_EXPR_STMT))
if (!reportWithOffset(ParseStrictError, pc->sc->strict, begin,
JSMSG_STRICT_CODE_LET_EXPR_STMT))
{
return null();
}
/*
* If this is really an expression in let statement guise, then we
* need to wrap the PNK_LET node in a PNK_SEMI node so that we pop
* the return value of the expression.
* need to wrap the PNK_LETEXPR node in a PNK_SEMI node so that we
* pop the return value of the expression.
*/
needExprStmt = true;
letContext = LetExpression;
@ -3711,14 +3706,22 @@ Parser<ParseHandler>::letBlock(LetContext letContext)
handler.setLexicalScopeBody(block, expr);
PopStatementPC(tokenStream, pc);
handler.setEndPosition(pnlet, pos().end);
TokenPos letPos(begin, pos().end);
if (needExprStmt) {
if (!MatchOrInsertSemicolon(tokenStream))
if (letContext == LetExpression) {
if (needExprStmt) {
if (!MatchOrInsertSemicolon(tokenStream))
return null();
}
Node letExpr = handler.newLetExpression(vars, block, letPos);
if (!letExpr)
return null();
return handler.newExprStatement(pnlet, pos().end);
return needExprStmt ? handler.newExprStatement(letExpr, pos().end) : letExpr;
}
return pnlet;
return handler.newLetBlock(vars, block, letPos);
}
template <typename ParseHandler>
@ -4097,27 +4100,44 @@ Parser<SyntaxParseHandler>::lexicalDeclaration(bool)
template <>
ParseNode *
Parser<FullParseHandler>::letStatement()
Parser<FullParseHandler>::letDeclarationOrBlock()
{
handler.disableSyntaxParser();
/* Check for a let statement or let expression. */
ParseNode *pn;
TokenKind tt;
if (!tokenStream.peekToken(&tt))
return null();
if (tt == TOK_LP) {
pn = letBlock(LetStatement);
MOZ_ASSERT_IF(pn, pn->isKind(PNK_LET) || pn->isKind(PNK_SEMI));
} else {
pn = lexicalDeclaration(/* isConst = */ false);
ParseNode *node = deprecatedLetBlockOrExpression(LetStatement);
if (!node)
return nullptr;
if (node->isKind(PNK_LETBLOCK)) {
MOZ_ASSERT(node->isArity(PN_BINARY));
} else {
MOZ_ASSERT(node->isKind(PNK_SEMI));
MOZ_ASSERT(node->pn_kid->isKind(PNK_LETEXPR));
MOZ_ASSERT(node->pn_kid->isArity(PN_BINARY));
}
return node;
}
return pn;
ParseNode *decl = lexicalDeclaration(/* isConst = */ false);
if (!decl)
return nullptr;
// let-declarations at global scope are currently treated as plain old var.
// See bug 589199.
MOZ_ASSERT(decl->isKind(PNK_LET) || decl->isKind(PNK_VAR));
MOZ_ASSERT(decl->isArity(PN_LIST));
return decl;
}
template <>
SyntaxParseHandler::Node
Parser<SyntaxParseHandler>::letStatement()
Parser<SyntaxParseHandler>::letDeclarationOrBlock()
{
JS_ALWAYS_FALSE(abortIfSyntaxParser());
return SyntaxParseHandler::NodeFailure;
@ -4655,7 +4675,7 @@ Parser<FullParseHandler>::forStatement()
if (!tokenStream.peekToken(&tt))
return null();
if (tt == TOK_LP) {
pn1 = letBlock(LetExpression);
pn1 = deprecatedLetBlockOrExpression(LetExpression);
} else {
isForDecl = true;
blockObj = StaticBlockObject::create(context);
@ -4928,11 +4948,7 @@ Parser<FullParseHandler>::forStatement()
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 handler.newLetBlock(forLetDecl, forLetImpliedBlock, forLoop->pn_pos);
}
return forLoop;
}
@ -5812,7 +5828,7 @@ Parser<ParseHandler>::statement(bool canHaveDirectives)
}
case TOK_LET:
return letStatement();
return letDeclarationOrBlock();
case TOK_IMPORT:
return importDeclaration();
case TOK_EXPORT:
@ -8129,7 +8145,7 @@ Parser<ParseHandler>::primaryExpr(TokenKind tt, InvokedPrediction invoked)
return objectLiteral();
case TOK_LET:
return letBlock(LetExpression);
return deprecatedLetBlockOrExpression(LetExpression);
case TOK_LP: {
TokenKind next;

View File

@ -557,7 +557,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
Node debuggerStatement();
Node lexicalDeclaration(bool isConst);
Node letStatement();
Node letDeclarationOrBlock();
Node importDeclaration();
Node exportDeclaration();
Node expressionStatement(InvokedPrediction invoked = PredictUninvoked);
@ -614,7 +614,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
Node generatorComprehension(uint32_t begin);
bool argumentList(Node listNode, bool *isSpread);
Node letBlock(LetContext letContext);
Node deprecatedLetBlockOrExpression(LetContext letContext);
Node destructuringExpr(BindData<ParseHandler> *data, TokenKind tt);
Node destructuringExprWithoutYield(BindData<ParseHandler> *data, TokenKind tt, unsigned msg);

View File

@ -246,6 +246,14 @@ class SyntaxParseHandler
Node newLexicalScope(ObjectBox *blockbox) { return NodeGeneric; }
void setLexicalScopeBody(Node block, Node body) {}
Node newLetExpression(Node vars, Node block, const TokenPos &pos) {
return NodeGeneric;
}
Node newLetBlock(Node vars, Node block, const TokenPos &pos) {
return NodeGeneric;
}
bool finishInitializerAssignment(Node pn, Node init, JSOp op) { return true; }
void setBeginPosition(Node pn, Node oth) {}

View File

@ -2367,11 +2367,12 @@ ASTSerializer::statement(ParseNode *pn, MutableHandleValue dst)
case PNK_GLOBALCONST:
return declaration(pn, dst);
case PNK_LETBLOCK:
return let(pn, false, dst);
case PNK_LET:
case PNK_CONST:
return pn->isArity(PN_BINARY)
? let(pn, false, dst)
: declaration(pn, dst);
return declaration(pn, dst);
case PNK_IMPORT:
return importDeclaration(pn, dst);
@ -3067,7 +3068,7 @@ ASTSerializer::expression(ParseNode *pn, MutableHandleValue dst)
LOCAL_ASSERT(pn->pn_count == 1);
return comprehension(pn->pn_head, dst);
case PNK_LET:
case PNK_LETEXPR:
return let(pn, true, dst);
default: