Remove support for non-standard let expressions, part 1: code.

Tag #773.
This commit is contained in:
Pale Moon
2017-01-08 03:52:56 +01:00
committed by roytam1
parent 2a9ab62e22
commit 563619e5f0
13 changed files with 45 additions and 196 deletions
+30 -108
View File
@@ -2924,7 +2924,7 @@ Parser<ParseHandler>::reportRedeclaration(Node pn, Definition::Kind redeclKind,
}
/*
* Define a lexical binding in a block, let-expression, or comprehension scope. pc
* Define a lexical binding in a block or comprehension scope. pc
* must already be in such a scope.
*
* Throw a SyntaxError if 'atom' is an invalid name. Otherwise create a
@@ -3613,13 +3613,13 @@ Parser<SyntaxParseHandler>::pushLetScope(HandleStaticBlockObject blockObj, StmtI
}
/*
* Parse a let block statement or let expression (determined by 'letContext').
* Parse a let block statement.
* In both cases, bindings are not hoisted to the top of the enclosing block
* and thus must be carefully injected between variables() and the let body.
*/
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::deprecatedLetBlockOrExpression(LetContext letContext)
Parser<ParseHandler>::deprecatedLetBlock()
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LET));
@@ -3642,82 +3642,22 @@ Parser<ParseHandler>::deprecatedLetBlockOrExpression(LetContext letContext)
if (!block)
return null();
bool needExprStmt = false;
if (letContext == LetStatement) {
bool matched;
if (!tokenStream.matchToken(&matched, TOK_LC, TokenStream::Operand))
return null();
if (!matched) {
/*
* Strict mode eliminates a grammar ambiguity with unparenthesized
* LetExpressions in an ExpressionStatement. If followed immediately
* by an arguments list, it's ambiguous whether the let expression
* is the callee or the call is inside the let expression body.
*
* function id(x) { return x; }
* var x = "outer";
* // Does this parse as
* // (let (loc = "inner") id)(loc) // "outer"
* // or as
* // let (loc = "inner") (id(loc)) // "inner"
* let (loc = "inner") id(loc);
*
* See bug 569464.
*/
if (!reportWithOffset(ParseStrictError, pc->sc->strict, begin,
JSMSG_STRICT_CODE_LET_EXPR_STMT))
{
return null();
}
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_LET);
Node expr = statements(yieldHandling);
if (!expr)
return null();
MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LET);
addTelemetry(JSCompartment::DeprecatedLetBlock);
if (!report(ParseWarning, pc->sc->strict(), expr, JSMSG_DEPRECATED_LET_BLOCK))
return null();
/*
* If this is really an expression in let statement guise, then we
* 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;
}
}
Node expr;
if (letContext == LetStatement) {
expr = statements();
if (!expr)
return null();
MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LET);
addTelemetry(JSCompartment::DeprecatedLetBlock);
if (!report(ParseWarning, pc->sc->strict, expr, JSMSG_DEPRECATED_LET_BLOCK))
return null();
} else {
MOZ_ASSERT(letContext == LetExpression);
expr = assignExpr();
if (!expr)
return null();
addTelemetry(JSCompartment::DeprecatedLetExpression);
if (!report(ParseWarning, pc->sc->strict, expr, JSMSG_DEPRECATED_LET_EXPRESSION))
return null();
}
handler.setLexicalScopeBody(block, expr);
PopStatementPC(tokenStream, pc);
TokenPos letPos(begin, pos().end);
if (letContext == LetExpression) {
if (needExprStmt) {
if (!MatchOrInsertSemicolon(tokenStream))
return null();
}
Node letExpr = handler.newLetExpression(vars, block, letPos);
if (!letExpr)
return null();
return needExprStmt ? handler.newExprStatement(letExpr, pos().end) : letExpr;
}
return handler.newLetBlock(vars, block, letPos);
}
@@ -4101,23 +4041,17 @@ Parser<FullParseHandler>::letDeclarationOrBlock()
{
handler.disableSyntaxParser();
/* Check for a let statement or let expression. */
/* Check for a let statement. */
TokenKind tt;
if (!tokenStream.peekToken(&tt))
return null();
if (tt == TOK_LP) {
ParseNode* node = deprecatedLetBlockOrExpression(LetStatement);
ParseNode* node = deprecatedLetBlock();
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));
}
MOZ_ASSERT(node->isKind(PNK_LETBLOCK));
MOZ_ASSERT(node->isArity(PN_BINARY));
return node;
}
@@ -4629,8 +4563,7 @@ Parser<FullParseHandler>::forStatement()
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
/*
* True if we have 'for (var/let/const ...)', except in the oddball case
* where 'let' begins a let-expression in 'for (let (...) ...)'.
* True if we have 'for (var/let/const ...)'.
*/
bool isForDecl = false;
@@ -4669,18 +4602,12 @@ Parser<FullParseHandler>::forStatement()
handler.disableSyntaxParser();
bool constDecl = tt == TOK_CONST;
tokenStream.consumeKnownToken(tt);
if (!tokenStream.peekToken(&tt))
isForDecl = true;
blockObj = StaticBlockObject::create(context);
if (!blockObj)
return null();
if (tt == TOK_LP) {
pn1 = deprecatedLetBlockOrExpression(LetExpression);
} else {
isForDecl = true;
blockObj = StaticBlockObject::create(context);
if (!blockObj)
return null();
pn1 = variables(constDecl ? PNK_CONST : PNK_LET, nullptr, blockObj,
DontHoistVars);
}
pn1 = variables(constDecl ? PNK_CONST : PNK_LET, nullptr, blockObj,
DontHoistVars);
} else {
pn1 = expr();
}
@@ -6695,9 +6622,7 @@ LegacyCompExprTransplanter::transplant(ParseNode* pn)
// The one remaining thing to patch up is the block scope depth. We need to
// compute the maximum block scope depth of a function, so we know how much
// space to reserve in the fixed part of a stack frame. Normally this is done
// whenever we leave a statement, via AccumulateBlockScopeDepth. However if the
// head has a let expression, we need to re-assign that depth to the tail of the
// comprehension.
// whenever we leave a statement, via AccumulateBlockScopeDepth.
//
// Thing is, we don't actually know what that depth is, because the only
// information we keep is the maximum nested depth within a statement, so we
@@ -6768,10 +6693,9 @@ Parser<FullParseHandler>::legacyComprehensionTail(ParseNode* bodyExpr, unsigned
* the comprehension's block scope. We allocate that id or one above it
* here, by calling PushLexicalScope.
*
* In the case of a comprehension expression that has nested blocks
* (e.g., let expressions), we will allocate a higher blockid but then
* slide all blocks "to the right" to make room for the comprehension's
* block scope.
* In the case of a comprehension expression that has nested blocks,
* we will allocate a higher blockid but then slide all blocks "to the
* right" to make room for the comprehension's block scope.
*/
adjust = pc->blockid();
pn = pushLexicalScope(&stmtInfo);
@@ -7804,9 +7728,10 @@ Parser<ParseHandler>::arrayInitializer()
*
* [i * j for (i in o) for (j in p) if (i != j)]
*
* translates to roughly the following let expression:
* translates to roughly the following code:
*
* let (array = new Array, i, j) {
* {
* let array = new Array, i, j;
* for (i in o) let {
* for (j in p)
* if (i != j)
@@ -8152,9 +8077,6 @@ Parser<ParseHandler>::primaryExpr(TokenKind tt, InvokedPrediction invoked)
case TOK_LC:
return objectLiteral();
case TOK_LET:
return deprecatedLetBlockOrExpression(LetExpression);
case TOK_LP: {
TokenKind next;
if (!tokenStream.peekToken(&next, TokenStream::Operand))