mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-09-09 04:54:33 +00:00
#430: refactor for loops from M1233249
This commit is contained in:
parent
a62ee9ff96
commit
b2141ff526
@ -609,6 +609,11 @@ class FullParseHandler
|
||||
return pn;
|
||||
}
|
||||
|
||||
ParseNode* newComprehensionBinding(ParseNode* kid) {
|
||||
MOZ_ASSERT(kid->isKind(PNK_NAME));
|
||||
return new_<ListNode>(PNK_LET, JSOP_NOP, kid);
|
||||
}
|
||||
|
||||
ParseNode* newForHead(ParseNodeKind kind, ParseNode* pn1, ParseNode* pn2, ParseNode* pn3,
|
||||
const TokenPos& pos)
|
||||
{
|
||||
@ -616,6 +621,14 @@ class FullParseHandler
|
||||
return new_<TernaryNode>(kind, JSOP_NOP, pn1, pn2, pn3, pos);
|
||||
}
|
||||
|
||||
void initForLetBlock(ParseNode* forLetImpliedBlock, ParseNode* nestedForLoop) {
|
||||
MOZ_ASSERT(forLetImpliedBlock->isKind(PNK_LEXICALSCOPE));
|
||||
MOZ_ASSERT(nestedForLoop->isKind(PNK_FOR));
|
||||
|
||||
forLetImpliedBlock->pn_expr = nestedForLoop;
|
||||
forLetImpliedBlock->pn_pos = nestedForLoop->pn_pos;
|
||||
}
|
||||
|
||||
ParseNode* newSwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* caseList) {
|
||||
TokenPos pos(begin, caseList->pn_pos.end);
|
||||
return new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, pos, discriminant, caseList);
|
||||
@ -798,28 +811,60 @@ class FullParseHandler
|
||||
return pn->pn_pos;
|
||||
}
|
||||
|
||||
bool isDeclarationKind(ParseNodeKind kind) {
|
||||
return kind == PNK_VAR || kind == PNK_LET || kind == PNK_CONST;
|
||||
}
|
||||
|
||||
ParseNode* newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind != PNK_VAR);
|
||||
return new_<ListNode>(kind, op, pos());
|
||||
}
|
||||
ParseNode* newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) {
|
||||
return new_<ListNode>(kind, op, TokenPos(begin, begin + 1));
|
||||
}
|
||||
ParseNode* newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
|
||||
MOZ_ASSERT(!isDeclarationKind(kind));
|
||||
return new_<ListNode>(kind, op, pos());
|
||||
}
|
||||
|
||||
/* New list with one initial child node. kid must be non-null. */
|
||||
ParseNode* newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(!isDeclarationKind(kind));
|
||||
return new_<ListNode>(kind, op, TokenPos(begin, begin + 1));
|
||||
}
|
||||
|
||||
ParseNode* newList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind != PNK_VAR);
|
||||
MOZ_ASSERT(!isDeclarationKind(kind));
|
||||
return new_<ListNode>(kind, op, kid);
|
||||
}
|
||||
|
||||
ParseNode* newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(isDeclarationKind(kind));
|
||||
return new_<ListNode>(kind, op, pos());
|
||||
}
|
||||
|
||||
ParseNode* newDeclarationList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
|
||||
MOZ_ASSERT(isDeclarationKind(kind));
|
||||
return new_<ListNode>(kind, op, kid);
|
||||
}
|
||||
|
||||
bool isDeclarationList(ParseNode* node) {
|
||||
return isDeclarationKind(node->getKind());
|
||||
}
|
||||
|
||||
bool declarationIsVar(ParseNode* node) {
|
||||
MOZ_ASSERT(isDeclarationList(node));
|
||||
return node->isKind(PNK_VAR);
|
||||
}
|
||||
|
||||
bool declarationIsLet(ParseNode* node) {
|
||||
MOZ_ASSERT(isDeclarationList(node));
|
||||
return node->isKind(PNK_LET);
|
||||
}
|
||||
|
||||
bool declarationIsConst(ParseNode* node) {
|
||||
MOZ_ASSERT(isDeclarationList(node));
|
||||
return node->isKind(PNK_CONST);
|
||||
}
|
||||
|
||||
ParseNode* singleBindingFromDeclaration(ParseNode* decl) {
|
||||
MOZ_ASSERT(isDeclarationList(decl));
|
||||
MOZ_ASSERT(decl->pn_count == 1);
|
||||
return decl->pn_head;
|
||||
}
|
||||
|
||||
ParseNode* newCatchList() {
|
||||
return new_<ListNode>(PNK_CATCHLIST, JSOP_NOP, pos());
|
||||
}
|
||||
|
@ -775,10 +775,6 @@ Parser<FullParseHandler>::cloneParseTree(ParseNode* opn)
|
||||
return pn;
|
||||
}
|
||||
|
||||
template <>
|
||||
ParseNode*
|
||||
Parser<FullParseHandler>::cloneLeftHandSide(ParseNode* opn);
|
||||
|
||||
/*
|
||||
* Used by Parser::cloneLeftHandSide to clone a default expression
|
||||
* in the form of
|
||||
@ -891,6 +887,16 @@ Parser<FullParseHandler>::cloneLeftHandSide(ParseNode* opn)
|
||||
return pn;
|
||||
}
|
||||
|
||||
template <>
|
||||
SyntaxParseHandler::Node
|
||||
Parser<SyntaxParseHandler>::cloneLeftHandSide(Node node)
|
||||
{
|
||||
// See the comment in SyntaxParseHandler::singleBindingFromDeclaration for
|
||||
// why this is okay.
|
||||
MOZ_ASSERT(node == SyntaxParseHandler::NodeUnparenthesizedName);
|
||||
return SyntaxParseHandler::NodeGeneric;
|
||||
}
|
||||
|
||||
} /* namespace frontend */
|
||||
} /* namespace js */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,12 +4,12 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* JS parser. */
|
||||
|
||||
#ifndef frontend_Parser_h
|
||||
#define frontend_Parser_h
|
||||
|
||||
/*
|
||||
* JS parser definitions.
|
||||
*/
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
#include "jspubtd.h"
|
||||
|
||||
@ -669,7 +669,21 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
Node ifStatement(YieldHandling yieldHandling);
|
||||
Node doWhileStatement(YieldHandling yieldHandling);
|
||||
Node whileStatement(YieldHandling yieldHandling);
|
||||
|
||||
Node forStatement(YieldHandling yieldHandling);
|
||||
bool forHeadStart(YieldHandling yieldHandling,
|
||||
ParseNodeKind* forHeadKind,
|
||||
Node* forInitialPart,
|
||||
mozilla::Maybe<AutoPushStmtInfoPC>& letStmt,
|
||||
MutableHandle<StaticBlockObject*> blockObj,
|
||||
Node* forLetImpliedBlock,
|
||||
Node* forInOrOfExpression);
|
||||
bool validateForInOrOfLHSExpression(Node target);
|
||||
Node expressionAfterForInOrOf(ParseNodeKind forHeadKind, YieldHandling yieldHandling);
|
||||
|
||||
void assertCurrentLexicalStaticBlockIs(ParseContext<ParseHandler>* pc,
|
||||
Handle<StaticBlockObject*> blockObj);
|
||||
|
||||
Node switchStatement(YieldHandling yieldHandling);
|
||||
Node continueStatement(YieldHandling yieldHandling);
|
||||
Node breakStatement(YieldHandling yieldHandling);
|
||||
@ -685,11 +699,59 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
Node exportDeclaration();
|
||||
Node expressionStatement(YieldHandling yieldHandling,
|
||||
InvokedPrediction invoked = PredictUninvoked);
|
||||
Node variables(YieldHandling yieldHandling,
|
||||
ParseNodeKind kind,
|
||||
ForInitLocation location,
|
||||
bool* psimple = nullptr, StaticBlockObject* blockObj = nullptr,
|
||||
VarContext varContext = HoistVars);
|
||||
|
||||
// Declaration parsing. The main entrypoint is Parser::declarationList,
|
||||
// with sub-functionality split out into the remaining methods.
|
||||
|
||||
// |blockObj| may be non-null only when |kind| corresponds to a lexical
|
||||
// declaration (that is, PNK_LET or PNK_CONST).
|
||||
//
|
||||
// The for* parameters, for normal declarations, should be null/ignored.
|
||||
// They should be non-null only when Parser::forHeadStart parses a
|
||||
// declaration at the start of a for-loop head.
|
||||
//
|
||||
// In this case, on success |*forHeadKind| is PNK_FORHEAD, PNK_FORIN, or
|
||||
// PNK_FOROF, corresponding to the three for-loop kinds. The precise value
|
||||
// indicates what was parsed.
|
||||
//
|
||||
// If parsing recognized a for(;;) loop, the next token is the ';' within
|
||||
// the loop-head that separates the init/test parts.
|
||||
//
|
||||
// Otherwise, for for-in/of loops, the next token is the ')' ending the
|
||||
// loop-head. Additionally, the expression that the loop iterates over was
|
||||
// parsed into |*forInOrOfExpression|.
|
||||
Node declarationList(YieldHandling yieldHandling,
|
||||
ParseNodeKind kind,
|
||||
StaticBlockObject* blockObj = nullptr,
|
||||
ParseNodeKind* forHeadKind = nullptr,
|
||||
Node* forInOrOfExpression = nullptr);
|
||||
|
||||
// The items in a declaration list are either patterns or names, with or
|
||||
// without initializers. These two methods parse a single pattern/name and
|
||||
// any associated initializer -- and if parsing an |initialDeclaration|
|
||||
// will, if parsing in a for-loop head (as specified by |forHeadKind| being
|
||||
// non-null), consume additional tokens up to the closing ')' in a
|
||||
// for-in/of loop head, returning the iterated expression in
|
||||
// |*forInOrOfExpression|. (An "initial declaration" is the first
|
||||
// declaration in a declaration list: |a| but not |b| in |var a, b|, |{c}|
|
||||
// but not |d| in |let {c} = 3, d|.)
|
||||
Node declarationPattern(Node decl, TokenKind tt, BindData<ParseHandler>* data,
|
||||
bool initialDeclaration, YieldHandling yieldHandling,
|
||||
ParseNodeKind* forHeadKind, Node* forInOrOfExpression);
|
||||
Node declarationName(Node decl, TokenKind tt, BindData<ParseHandler>* data,
|
||||
bool initialDeclaration, YieldHandling yieldHandling,
|
||||
ParseNodeKind* forHeadKind, Node* forInOrOfExpression);
|
||||
|
||||
// Having parsed a name (not found in a destructuring pattern) declared by
|
||||
// a declaration, with the current token being the '=' separating the name
|
||||
// from its initializer, parse and bind that initializer -- and possibly
|
||||
// consume trailing in/of and subsequent expression, if so directed by
|
||||
// |forHeadKind|.
|
||||
bool initializerInNameDeclaration(Node decl, Node binding, Handle<PropertyName*> name,
|
||||
BindData<ParseHandler>* data, bool initialDeclaration,
|
||||
YieldHandling yieldHandling, ParseNodeKind* forHeadKind,
|
||||
Node* forInOrOfExpression);
|
||||
|
||||
Node expr(InHandling inHandling, YieldHandling yieldHandling,
|
||||
TripledotHandling tripledotHandling,
|
||||
InvokedPrediction invoked = PredictUninvoked);
|
||||
@ -782,7 +844,8 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
CompoundAssignment,
|
||||
KeyedDestructuringAssignment,
|
||||
IncrementAssignment,
|
||||
DecrementAssignment
|
||||
DecrementAssignment,
|
||||
ForInOrOfTarget
|
||||
};
|
||||
|
||||
bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor);
|
||||
@ -801,10 +864,6 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
bool finishFunctionDefinition(Node pn, FunctionBox* funbox, Node body);
|
||||
bool addFreeVariablesFromLazyFunction(JSFunction* fun, ParseContext<ParseHandler>* pc);
|
||||
|
||||
bool isValidForStatementLHS(Node pn1, JSVersion version, bool forDecl, bool forEach,
|
||||
ParseNodeKind headKind);
|
||||
bool checkForHeadConstInitializers(Node pn1);
|
||||
|
||||
// Use when the current token is TOK_NAME and is known to be 'let'.
|
||||
bool shouldParseLetDeclaration(bool* parseDeclOut);
|
||||
|
||||
@ -876,8 +935,10 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
bool bindUninitialized(BindData<ParseHandler>* data, HandlePropertyName name, Node pn);
|
||||
bool bindUninitialized(BindData<ParseHandler>* data, Node pn);
|
||||
bool makeSetCall(Node node, unsigned errnum);
|
||||
Node cloneDestructuringDefault(Node opn);
|
||||
|
||||
Node cloneForInOrOfDeclarationForAssignment(Node decl);
|
||||
Node cloneLeftHandSide(Node opn);
|
||||
Node cloneDestructuringDefault(Node opn);
|
||||
Node cloneParseTree(Node opn);
|
||||
|
||||
Node newNumber(const Token& tok) {
|
||||
|
@ -42,11 +42,16 @@ class SyntaxParseHandler
|
||||
NodeGetProp,
|
||||
NodeStringExprStatement,
|
||||
NodeReturn,
|
||||
NodeHoistableDeclaration,
|
||||
NodeBreak,
|
||||
NodeThrow,
|
||||
NodeEmptyStatement,
|
||||
|
||||
NodeVarDeclaration,
|
||||
NodeLetDeclaration,
|
||||
NodeConstDeclaration,
|
||||
|
||||
NodeFunctionDefinition,
|
||||
|
||||
// This is needed for proper assignment-target handling. ES6 formally
|
||||
// requires function calls *not* pass IsValidSimpleAssignmentTarget,
|
||||
// but at last check there were still sites with |f() = 5| and similar
|
||||
@ -348,10 +353,10 @@ class SyntaxParseHandler
|
||||
|
||||
bool setLastFunctionArgumentDefault(Node funcpn, Node pn) { return true; }
|
||||
void setLastFunctionArgumentDestructuring(Node funcpn, Node pn) {}
|
||||
Node newFunctionDefinition() { return NodeHoistableDeclaration; }
|
||||
Node newFunctionDefinition() { return NodeFunctionDefinition; }
|
||||
void setFunctionBody(Node pn, Node kid) {}
|
||||
void setFunctionBox(Node pn, FunctionBox* funbox) {}
|
||||
Node newFunctionDefinitionForAnnexB(Node pn, Node assignment) { return NodeHoistableDeclaration; }
|
||||
Node newFunctionDefinitionForAnnexB(Node pn, Node assignment) { return NodeFunctionDefinition; }
|
||||
void addFunctionArgument(Node pn, Node argpn) {}
|
||||
|
||||
Node newForStatement(uint32_t begin, Node forHead, Node body, unsigned iflags) {
|
||||
@ -362,10 +367,23 @@ class SyntaxParseHandler
|
||||
return NodeGeneric;
|
||||
}
|
||||
|
||||
Node newComprehensionBinding(Node kid) {
|
||||
// Careful: we're asking this well after the name was parsed, so the
|
||||
// value returned may not correspond to |kid|'s actual name. But it
|
||||
// *will* be truthy iff |kid| was a name, so we're safe.
|
||||
MOZ_ASSERT(maybeUnparenthesizedName(kid));
|
||||
return NodeGeneric;
|
||||
}
|
||||
|
||||
Node newForHead(ParseNodeKind kind, Node decls, Node lhs, Node rhs, const TokenPos& pos) {
|
||||
return NodeGeneric;
|
||||
}
|
||||
|
||||
void initForLetBlock(Node forLetImpliedBlock, Node nestedForLoop) {
|
||||
MOZ_ASSERT(forLetImpliedBlock == NodeGeneric); // per newForStatement
|
||||
MOZ_ASSERT(nestedForLoop == NodeGeneric); // per newLexicalScope
|
||||
}
|
||||
|
||||
Node newLexicalScope(ObjectBox* blockbox) { return NodeGeneric; }
|
||||
void setLexicalScopeBody(Node block, Node body) {}
|
||||
|
||||
@ -391,22 +409,68 @@ class SyntaxParseHandler
|
||||
|
||||
Node newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind != PNK_VAR);
|
||||
MOZ_ASSERT(kind != PNK_LET);
|
||||
MOZ_ASSERT(kind != PNK_CONST);
|
||||
return NodeGeneric;
|
||||
}
|
||||
Node newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) {
|
||||
return NodeGeneric;
|
||||
}
|
||||
Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
|
||||
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
|
||||
return newList(kind, op);
|
||||
}
|
||||
Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind != PNK_VAR);
|
||||
return NodeGeneric;
|
||||
return newList(kind, op);
|
||||
}
|
||||
|
||||
Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
||||
if (kind == PNK_VAR)
|
||||
return NodeVarDeclaration;
|
||||
if (kind == PNK_LET)
|
||||
return NodeLetDeclaration;
|
||||
MOZ_ASSERT(kind == PNK_CONST);
|
||||
return NodeConstDeclaration;
|
||||
}
|
||||
Node newDeclarationList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
|
||||
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
|
||||
return newDeclarationList(kind, op);
|
||||
}
|
||||
|
||||
bool isDeclarationList(Node node) {
|
||||
return node == NodeVarDeclaration ||
|
||||
node == NodeLetDeclaration ||
|
||||
node == NodeConstDeclaration;
|
||||
}
|
||||
|
||||
bool declarationIsVar(Node node) {
|
||||
MOZ_ASSERT(isDeclarationList(node));
|
||||
return node == NodeVarDeclaration;
|
||||
}
|
||||
|
||||
bool declarationIsLet(Node node) {
|
||||
MOZ_ASSERT(isDeclarationList(node));
|
||||
return node == NodeLetDeclaration;
|
||||
}
|
||||
|
||||
bool declarationIsConst(Node node) {
|
||||
MOZ_ASSERT(isDeclarationList(node));
|
||||
return node == NodeConstDeclaration;
|
||||
}
|
||||
|
||||
Node singleBindingFromDeclaration(Node decl) {
|
||||
MOZ_ASSERT(isDeclarationList(decl));
|
||||
|
||||
// This is, unfortunately, very dodgy. Obviously NodeVarDeclaration
|
||||
// can store no info on the arbitrary number of bindings it could
|
||||
// contain.
|
||||
//
|
||||
// But this method is called only for cloning for-in/of declarations
|
||||
// as initialization targets. That context simplifies matters. If the
|
||||
// binding is a single name, it'll always syntax-parse (or it would
|
||||
// already have been rejected as assigning/binding a forbidden name).
|
||||
// Otherwise the binding is a destructuring pattern. But syntax
|
||||
// parsing would *already* have aborted when it saw a destructuring
|
||||
// pattern. So we can just say any old thing here, because the only
|
||||
// time we'll be wrong is a case that syntax parsing has already
|
||||
// rejected. Use NodeUnparenthesizedName so the SyntaxParseHandler
|
||||
// Parser::cloneLeftHandSide can assert it sees only this.
|
||||
return NodeUnparenthesizedName;
|
||||
}
|
||||
|
||||
Node newCatchList() {
|
||||
@ -422,7 +486,9 @@ class SyntaxParseHandler
|
||||
list == NodeUnparenthesizedArray ||
|
||||
list == NodeUnparenthesizedObject ||
|
||||
list == NodeUnparenthesizedCommaExpr ||
|
||||
list == NodeHoistableDeclaration ||
|
||||
list == NodeVarDeclaration ||
|
||||
list == NodeLetDeclaration ||
|
||||
list == NodeConstDeclaration ||
|
||||
list == NodeFunctionCall);
|
||||
}
|
||||
|
||||
@ -455,7 +521,9 @@ class SyntaxParseHandler
|
||||
}
|
||||
|
||||
bool isStatementPermittedAfterReturnStatement(Node pn) {
|
||||
return pn == NodeHoistableDeclaration || pn == NodeBreak || pn == NodeThrow ||
|
||||
return pn == NodeFunctionDefinition || pn == NodeVarDeclaration ||
|
||||
pn == NodeBreak ||
|
||||
pn == NodeThrow ||
|
||||
pn == NodeEmptyStatement;
|
||||
}
|
||||
|
||||
|
@ -16,14 +16,95 @@ eval(`[...let] = [];`);
|
||||
eval(`function let() { return 42; } assertEq(let(), 42);`)
|
||||
eval(`let {x:x} = {x:42}; assertEq(x, 42);`);
|
||||
eval(`let [x] = [42]; assertEq(x, 42);`);
|
||||
|
||||
eval(`for (let x in [1]) { assertEq(x, "0"); }`);
|
||||
expectError(`for (const x in [1]) { assertEq(x, "0"); }`); // XXX bug 449811
|
||||
|
||||
eval(`for (let x of [1]) { assertEq(x, 1); }`);
|
||||
expectError(`for (const x of [1]) { assertEq(x, 1); }`); // XXX bug 449811
|
||||
|
||||
eval(`for (let i = 0; i < 1; i++) { assertEq(i, 0); }`);
|
||||
eval(`for (let in [1]) { assertEq(let, "0"); }`);
|
||||
eval(`var done = false; for (const i = 0; !done; done = true) { assertEq(i, 0); }`);
|
||||
|
||||
eval(`for (let of of [1]) { assertEq(of, 1); }`);
|
||||
eval(`for (let/1;;) { break; }`);
|
||||
expectError(`for (const of of [1]) { assertEq(of, 1); }`); // XXX bug 449811
|
||||
|
||||
eval(`try { throw 17; } catch (let) { assertEq(let, 17); }`);
|
||||
eval(`try { throw [17]; } catch ([let]) { assertEq(let, 17); }`);
|
||||
eval(`try { throw { x: 17 }; } catch ({ x: let }) { assertEq(let, 17); }`);
|
||||
eval(`try { throw {}; } catch ({ x: let = 17 }) { assertEq(let, 17); }`);
|
||||
|
||||
expectError(`try { throw [17, 42]; } catch ([let, let]) {}`);
|
||||
|
||||
eval(`for (let in [1]) { assertEq(let, "0"); }`);
|
||||
eval(`for (let / 1; ; ) { break; }`);
|
||||
expectError(`let = {}; for (let.x of;;);`);
|
||||
expectError(`for (let of [1]) { }`);
|
||||
expectError(`let let = 42;`);
|
||||
|
||||
expectError(`for (let let in [1]) { }`);
|
||||
expectError(`for (const let in [1]) { }`);
|
||||
|
||||
expectError(`for (let let of [1]) { }`);
|
||||
expectError(`for (const let of [1]) { }`);
|
||||
|
||||
expectError(`for (let let = 17; false; ) { }`);
|
||||
expectError(`for (const let = 17; false; ) { }`);
|
||||
|
||||
expectError(`for (let [let] = 17; false; ) { }`);
|
||||
expectError(`for (const [let] = 17; false; ) { }`);
|
||||
|
||||
expectError(`for (let [let = 42] = 17; false; ) { }`);
|
||||
expectError(`for (const [let = 42] = 17; false; ) { }`);
|
||||
|
||||
expectError(`for (let { x: let } = 17; false; ) { }`);
|
||||
expectError(`for (const { x: let } = 17; false; ) { }`);
|
||||
|
||||
expectError(`for (let { x: let = 42 } = 17; false; ) { }`);
|
||||
expectError(`for (const { x: let = 42 } = 17; false; ) { }`);
|
||||
|
||||
expectError("let\nlet;");
|
||||
expectError("const\nlet;");
|
||||
|
||||
expectError(`let let = 17;`);
|
||||
expectError(`const let = 17;`);
|
||||
|
||||
expectError(`let [let] = 17;`);
|
||||
expectError(`const [let] = 17;`);
|
||||
|
||||
expectError(`let [let = 42] = 17;`);
|
||||
expectError(`const [let = 42] = 17;`);
|
||||
|
||||
expectError(`let {let} = 17;`);
|
||||
expectError(`const {let} = 17;`);
|
||||
|
||||
expectError(`let { let = 42 } = 17;`);
|
||||
expectError(`const { let = 42 } = 17;`);
|
||||
|
||||
expectError(`let { x: let } = 17;`);
|
||||
expectError(`const { x: let } = 17;`);
|
||||
|
||||
expectError(`let { x: let = 42 } = 17;`);
|
||||
expectError(`const { x: let = 42 } = 17;`);
|
||||
|
||||
expectError(`let { ['y']: let } = 17;`);
|
||||
expectError(`const { ['y']: let } = 17;`);
|
||||
|
||||
expectError(`let { ['y']: let = 42 } = 17;`);
|
||||
expectError(`const { ['y']: let = 42 } = 17;`);
|
||||
|
||||
expectError(`let { x: [let] } = { x: 17 };`);
|
||||
expectError(`const { x: [let] } = { x: 17 };`);
|
||||
|
||||
expectError(`let { x: [let = 42] } = { x: 17 };`);
|
||||
expectError(`const { x: [let = 42] } = { x: 17 };`);
|
||||
|
||||
expectError(`let [foo, let] = 42;`);
|
||||
expectError(`const [foo, let] = 42;`);
|
||||
|
||||
expectError(`let [foo, { let }] = [17, {}];`);
|
||||
expectError(`const [foo, { let }] = [17, {}];`);
|
||||
|
||||
expectError(`"use strict"; var let = 42;`);
|
||||
expectError(`"use strict"; function let() {}`);
|
||||
expectError(`"use strict"; for (let of [1]) {}`);
|
||||
expectError(`"use strict"; try {} catch (let) {}`);
|
||||
|
@ -199,8 +199,10 @@ MSG_DEF(JSMSG_BAD_DESTRUCT_PARENS, 0, JSEXN_SYNTAXERR, "destructuring patter
|
||||
MSG_DEF(JSMSG_BAD_DESTRUCT_DECL, 0, JSEXN_SYNTAXERR, "missing = in destructuring declaration")
|
||||
MSG_DEF(JSMSG_BAD_DUP_ARGS, 0, JSEXN_SYNTAXERR, "duplicate argument names not allowed in this context")
|
||||
MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 0, JSEXN_SYNTAXERR, "invalid for each loop")
|
||||
MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for/in left-hand side")
|
||||
MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value")
|
||||
MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for-in/of left-hand side")
|
||||
MSG_DEF(JSMSG_LEXICAL_DECL_DEFINES_LET,0, JSEXN_SYNTAXERR, "a lexical declaration can't define a 'let' binding")
|
||||
MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in 'for (X of Y)' must not start with 'let'")
|
||||
MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value")
|
||||
MSG_DEF(JSMSG_BAD_YIELD_SYNTAX, 0, JSEXN_SYNTAXERR, "yield expression must be parenthesized")
|
||||
MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX, 0, JSEXN_SYNTAXERR, "generator expression must be parenthesized")
|
||||
MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression")
|
||||
@ -265,7 +267,7 @@ MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage a
|
||||
MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal")
|
||||
MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character")
|
||||
MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module")
|
||||
MSG_DEF(JSMSG_INVALID_FOR_INOF_DECL_WITH_INIT,1,JSEXN_SYNTAXERR,"for-{0} loop head declarations may not have initializers")
|
||||
MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers")
|
||||
MSG_DEF(JSMSG_IN_AFTER_FOR_NAME, 0, JSEXN_SYNTAXERR, "missing 'in' or 'of' after for")
|
||||
MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found")
|
||||
MSG_DEF(JSMSG_LET_CLASS_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a class")
|
||||
@ -312,7 +314,7 @@ MSG_DEF(JSMSG_PAREN_BEFORE_WITH, 0, JSEXN_SYNTAXERR, "missing ( before wit
|
||||
MSG_DEF(JSMSG_PAREN_IN_PAREN, 0, JSEXN_SYNTAXERR, "missing ) in parenthetical")
|
||||
MSG_DEF(JSMSG_RC_AFTER_EXPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after export specifier list")
|
||||
MSG_DEF(JSMSG_RC_AFTER_IMPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after module specifier list")
|
||||
MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 1, JSEXN_TYPEERR, "redeclaration of identifier '{0}' in catch")
|
||||
MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 1, JSEXN_SYNTAXERR, "redeclaration of identifier '{0}' in catch")
|
||||
MSG_DEF(JSMSG_REDECLARED_PARAM, 1, JSEXN_TYPEERR, "redeclaration of formal parameter {0}")
|
||||
MSG_DEF(JSMSG_RESERVED_ID, 1, JSEXN_SYNTAXERR, "{0} is a reserved identifier")
|
||||
MSG_DEF(JSMSG_REST_WITH_DEFAULT, 0, JSEXN_SYNTAXERR, "rest parameter may not have a default")
|
||||
|
@ -20,7 +20,7 @@ function test()
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
expect = 'SyntaxError: invalid for/in left-hand side';
|
||||
expect = 'SyntaxError: invalid for-in/of left-hand side';
|
||||
actual = '';
|
||||
try
|
||||
{
|
||||
|
@ -29,11 +29,11 @@ namespace js {
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
|
||||
*/
|
||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 336;
|
||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 337;
|
||||
static const uint32_t XDR_BYTECODE_VERSION =
|
||||
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
|
||||
|
||||
static_assert(JSErr_Limit == 434,
|
||||
static_assert(JSErr_Limit == 436,
|
||||
"GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
|
||||
"removed MSG_DEFs from js.msg, you should increment "
|
||||
"XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
|
||||
|
Loading…
Reference in New Issue
Block a user