#430: implement destructuring default arguments from M932080 +test changes

This commit is contained in:
Cameron Kaiser 2017-08-23 20:48:44 -07:00
parent 289bb253c1
commit a9e9d0bb5f
58 changed files with 517 additions and 1033 deletions

View File

@ -717,7 +717,6 @@ template <typename ParseHandler>
Parser<ParseHandler>::~Parser()
{
MOZ_ASSERT(checkOptionsCalled);
alloc.release(tempPoolMark);
/*
@ -3865,6 +3864,70 @@ Parser<ParseHandler>::AutoPushStmtInfoPC::makeInnermostLexicalScope(StaticBlockO
return generateBlockId();
}
template <typename ParseHandler>
Parser<ParseHandler>::PossibleError::PossibleError(Parser<ParseHandler>& parser)
: parser_(parser)
{
state_ = ErrorState::None;
}
template <typename ParseHandler>
void
Parser<ParseHandler>::PossibleError::setPending(ParseReportKind kind, unsigned errorNumber,
bool strict)
{
// If we report an error later, we'll do it from the position where we set
// the state to pending.
offset_ = parser_.pos().begin;
reportKind_ = kind;
strict_ = strict;
errorNumber_ = errorNumber;
state_ = ErrorState::Pending;
}
template <typename ParseHandler>
void
Parser<ParseHandler>::PossibleError::setResolved()
{
state_ = ErrorState::None;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::PossibleError::hasError()
{
return state_ == ErrorState::Pending;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::PossibleError::checkForExprErrors()
{
bool err = hasError();
if (err) {
parser_.reportWithOffset(reportKind_, strict_, offset_, errorNumber_);
}
return !err;
}
template <typename ParseHandler>
void
Parser<ParseHandler>::PossibleError::transferErrorTo(PossibleError* other)
{
if (other) {
MOZ_ASSERT(this != other);
MOZ_ASSERT(!other->hasError());
// We should never allow fields to be copied between instances
// that point to different underlying parsers.
MOZ_ASSERT(&parser_ == &other->parser_);
other->offset_ = offset_;
other->reportKind_ = reportKind_;
other->errorNumber_ = errorNumber_;
other->strict_ = strict_;
other->state_ = state_;
}
}
template <typename ParseHandler>
static inline bool
OuterLet(ParseContext<ParseHandler>* pc, StmtInfoPC* stmt, HandleAtom atom)
@ -4301,7 +4364,8 @@ Parser<ParseHandler>::destructuringExpr(YieldHandling yieldHandling, BindData<Pa
MOZ_ASSERT(tokenStream.isCurrentTokenType(tt));
pc->inDeclDestructuring = true;
Node pn = primaryExpr(yieldHandling, TripledotProhibited, tt);
Node pn = primaryExpr(yieldHandling, TripledotProhibited,
nullptr /* possibleError */, tt);
pc->inDeclDestructuring = false;
if (!pn)
return null();
@ -4454,10 +4518,10 @@ Parser<ParseHandler>::expressionAfterForInOrOf(ParseNodeKind forHeadKind,
YieldHandling yieldHandling)
{
MOZ_ASSERT(forHeadKind == PNK_FORIN || forHeadKind == PNK_FOROF);
return forHeadKind == PNK_FOROF
Node pn = forHeadKind == PNK_FOROF
? assignExpr(InAllowed, yieldHandling, TripledotProhibited)
: expr(InAllowed, yieldHandling, TripledotProhibited);
return pn;
}
template <typename ParseHandler>
@ -4473,7 +4537,11 @@ Parser<ParseHandler>::declarationPattern(Node decl, TokenKind tt, BindData<Parse
Node pattern;
{
pc->inDeclDestructuring = true;
pattern = primaryExpr(yieldHandling, TripledotProhibited, tt);
// No possible error is required because we already know we're
// destructuring.
pattern = primaryExpr(yieldHandling, TripledotProhibited,
nullptr /* possibleError */ , tt);
pc->inDeclDestructuring = false;
}
if (!pattern)
@ -4518,7 +4586,14 @@ Parser<ParseHandler>::declarationPattern(Node decl, TokenKind tt, BindData<Parse
return null();
}
MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL);
TokenKind token;
if (!tokenStream.getToken(&token, TokenStream::None))
return null();
if (token != TOK_ASSIGN) {
report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_DECL);
return null();
}
Node init = assignExpr(forHeadKind ? InProhibited : InAllowed,
yieldHandling, TripledotProhibited);
@ -6653,7 +6728,6 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!catchName)
return null();
break;
case TOK_YIELD:
if (yieldHandling == YieldIsKeyword) {
report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield");
@ -7280,9 +7354,12 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirecti
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::expr(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling, InvokedPrediction invoked)
TripledotHandling tripledotHandling,
PossibleError* possibleError,
InvokedPrediction invoked)
{
Node pn = assignExpr(inHandling, yieldHandling, tripledotHandling, invoked);
Node pn = assignExpr(inHandling, yieldHandling, tripledotHandling,
possibleError, invoked);
if (!pn)
return null();
@ -7297,9 +7374,26 @@ Parser<ParseHandler>::expr(InHandling inHandling, YieldHandling yieldHandling,
return null();
while (true) {
pn = assignExpr(inHandling, yieldHandling, tripledotHandling);
// Additional calls to assignExpr should not reuse the possibleError
// which had been passed into the function. Otherwise we would lose
// information needed to determine whether or not we're dealing with
// a non-recoverable situation.
PossibleError possibleErrorInner(*this);
pn = assignExpr(inHandling, yieldHandling, tripledotHandling,
&possibleErrorInner);
if (!pn)
return null();
// If we find an error here we should report it immedately instead of
// passing it back out of the function.
if (possibleErrorInner.hasError()) {
// We begin by checking for an outer pending error since it would
// have occurred first.
if (possibleError->checkForExprErrors())
possibleErrorInner.checkForExprErrors();
return null();
}
handler.addList(seq, pn);
if (!tokenStream.matchToken(&matched, TOK_COMMA))
@ -7310,6 +7404,19 @@ Parser<ParseHandler>::expr(InHandling inHandling, YieldHandling yieldHandling,
return seq;
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::expr(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
InvokedPrediction invoked)
{
PossibleError possibleError(*this);
Node pn = expr(inHandling, yieldHandling, tripledotHandling, &possibleError, invoked);
if (!pn || !possibleError.checkForExprErrors())
return null();
return pn;
}
static const JSOp ParseNodeKindToJSOp[] = {
JSOP_OR,
JSOP_AND,
@ -7397,7 +7504,9 @@ Precedence(ParseNodeKind pnk) {
template <typename ParseHandler>
MOZ_ALWAYS_INLINE typename ParseHandler::Node
Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling, InvokedPrediction invoked)
TripledotHandling tripledotHandling,
PossibleError* possibleError,
InvokedPrediction invoked)
{
// Shift-reduce parser for the binary operator part of the JS expression
// syntax.
@ -7410,7 +7519,7 @@ Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling
Node pn;
for (;;) {
pn = unaryExpr(yieldHandling, tripledotHandling, invoked);
pn = unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked);
if (!pn)
return pn;
@ -7465,19 +7574,22 @@ Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling
template <typename ParseHandler>
MOZ_ALWAYS_INLINE typename ParseHandler::Node
Parser<ParseHandler>::condExpr1(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling, InvokedPrediction invoked)
TripledotHandling tripledotHandling,
PossibleError* possibleError,
InvokedPrediction invoked)
{
Node condition = orExpr1(inHandling, yieldHandling, tripledotHandling, invoked);
Node condition = orExpr1(inHandling, yieldHandling, tripledotHandling, possibleError, invoked);
if (!condition || !tokenStream.isCurrentTokenType(TOK_HOOK))
return condition;
Node thenExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
Node thenExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
possibleError);
if (!thenExpr)
return null();
MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND);
Node elseExpr = assignExpr(inHandling, yieldHandling, TripledotProhibited);
Node elseExpr = assignExpr(inHandling, yieldHandling, TripledotProhibited,
possibleError);
if (!elseExpr)
return null();
@ -7490,7 +7602,8 @@ Parser<ParseHandler>::condExpr1(InHandling inHandling, YieldHandling yieldHandli
template <typename ParseHandler>
bool
Parser<ParseHandler>::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor flavor)
Parser<ParseHandler>::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor flavor,
PossibleError* possibleError)
{
MOZ_ASSERT(flavor != KeyedDestructuringAssignment,
"destructuring must use special checking/marking code, not "
@ -7502,7 +7615,13 @@ Parser<ParseHandler>::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor
return false;
}
return checkDestructuringPattern(nullptr, target);
bool isDestructuring = checkDestructuringPattern(nullptr, target);
// Here we've successfully distinguished between destructuring and
// an object literal. In the case where "CoverInitializedName"
// syntax was used there will be a pending error that needs clearing.
if (possibleError && isDestructuring)
possibleError->setResolved();
return isDestructuring;
}
// All other permitted targets are simple.
@ -7530,9 +7649,12 @@ Parser<ParseHandler>::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling, InvokedPrediction invoked)
TripledotHandling tripledotHandling,
PossibleError* possibleError,
InvokedPrediction invoked)
{
JS_CHECK_RECURSION(context, return null());
MOZ_ASSERT(!possibleError->hasError());
// It's very common at this point to have a "detectably simple" expression,
// i.e. a name/number/string token followed by one of the following tokens
@ -7582,9 +7704,11 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
TokenStream::Position start(keepAtoms);
tokenStream.tell(&start);
Node lhs = condExpr1(inHandling, yieldHandling, tripledotHandling, invoked);
if (!lhs)
PossibleError possibleErrorInner(*this);
Node lhs = condExpr1(inHandling, yieldHandling, tripledotHandling, &possibleErrorInner, invoked);
if (!lhs) {
return null();
}
ParseNodeKind kind;
JSOp op;
@ -7604,6 +7728,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
case TOK_POWASSIGN: kind = PNK_POWASSIGN; op = JSOP_POW; break;
case TOK_ARROW: {
// A line terminator between ArrowParameters and the => should trigger a SyntaxError.
tokenStream.ungetToken();
TokenKind next = TOK_EOF;
@ -7666,24 +7791,42 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
default:
MOZ_ASSERT(!tokenStream.isCurrentTokenAssignment());
possibleErrorInner.transferErrorTo(possibleError);
tokenStream.ungetToken();
return lhs;
}
AssignmentFlavor flavor = kind == PNK_ASSIGN ? PlainAssignment : CompoundAssignment;
if (!checkAndMarkAsAssignmentLhs(lhs, flavor))
if (!checkAndMarkAsAssignmentLhs(lhs, flavor, &possibleErrorInner))
return null();
if (!possibleErrorInner.checkForExprErrors())
return null();
bool saved = pc->inDeclDestructuring;
pc->inDeclDestructuring = false;
Node rhs = assignExpr(inHandling, yieldHandling, TripledotProhibited);
Node rhs = assignExpr(inHandling, yieldHandling, TripledotProhibited,
possibleError);
pc->inDeclDestructuring = saved;
if (!rhs)
return null();
return handler.newAssignment(kind, lhs, rhs, pc, op);
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
InvokedPrediction invoked)
{
PossibleError possibleError(*this);
Node expr = assignExpr(inHandling, yieldHandling, tripledotHandling, &possibleError, invoked);
if (!expr || !possibleError.checkForExprErrors())
return null();
return expr;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::isValidSimpleAssignmentTarget(Node node,
@ -7808,8 +7951,9 @@ typename ParseHandler::Node
Parser<ParseHandler>::unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op,
uint32_t begin)
{
Node kid = unaryExpr(yieldHandling, TripledotProhibited);
if (!kid)
PossibleError possibleError(*this);
Node kid = unaryExpr(yieldHandling, TripledotProhibited, &possibleError);
if (!kid || !possibleError.checkForExprErrors())
return null();
return handler.newUnary(kind, op, begin, kid);
}
@ -7817,7 +7961,7 @@ Parser<ParseHandler>::unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kin
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling,
InvokedPrediction invoked)
PossibleError* possibleError, InvokedPrediction invoked)
{
JS_CHECK_RECURSION(context, return null());
@ -7849,7 +7993,7 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
// // Evaluates expression, triggering a runtime ReferenceError for
// // the undefined name.
// typeof (1, nonExistentName);
Node kid = unaryExpr(yieldHandling, TripledotProhibited);
Node kid = unaryExpr(yieldHandling, TripledotProhibited, possibleError);
if (!kid)
return null();
@ -7862,7 +8006,7 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
TokenKind tt2;
if (!tokenStream.getToken(&tt2, TokenStream::Operand))
return null();
Node pn2 = memberExpr(yieldHandling, TripledotProhibited, tt2, true);
Node pn2 = memberExpr(yieldHandling, TripledotProhibited, possibleError, tt2, true);
if (!pn2)
return null();
AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment;
@ -7874,7 +8018,7 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
}
case TOK_DELETE: {
Node expr = unaryExpr(yieldHandling, TripledotProhibited);
Node expr = unaryExpr(yieldHandling, TripledotProhibited, possibleError);
if (!expr)
return null();
@ -7890,7 +8034,7 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
}
default: {
Node pn = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true,
Node pn = memberExpr(yieldHandling, tripledotHandling, possibleError, tt, /* allowCallSyntax = */ true,
invoked);
if (!pn)
return null();
@ -8266,7 +8410,11 @@ Parser<FullParseHandler>::legacyComprehensionTail(ParseNode* bodyExpr, unsigned
case TOK_LB:
case TOK_LC:
pc->inDeclDestructuring = true;
pn3 = primaryExpr(YieldIsKeyword, TripledotProhibited, tt);
// No possible error is needed here either because we already
// know we are destructuring.
pn3 = primaryExpr(YieldIsKeyword, TripledotProhibited,
nullptr /* = possibleError */, tt);
pc->inDeclDestructuring = false;
if (!pn3)
return null();
@ -8935,7 +9083,8 @@ Parser<ParseHandler>::checkAndMarkSuperScope()
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling,
TokenKind tt, bool allowCallSyntax, InvokedPrediction invoked)
PossibleError* possibleError, TokenKind tt,
bool allowCallSyntax, InvokedPrediction invoked)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(tt));
@ -8959,7 +9108,8 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
// Gotten by tryNewTarget
tt = tokenStream.currentToken().type;
Node ctorExpr = memberExpr(yieldHandling, TripledotProhibited, tt, false, PredictInvoked);
Node ctorExpr = memberExpr(yieldHandling, TripledotProhibited,
possibleError, tt, false, PredictInvoked);
if (!ctorExpr)
return null();
@ -8984,7 +9134,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
if (!lhs)
return null();
} else {
lhs = primaryExpr(yieldHandling, tripledotHandling, tt, invoked);
lhs = primaryExpr(yieldHandling, tripledotHandling, possibleError, tt, invoked);
if (!lhs)
return null();
}
@ -9015,7 +9165,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
return null();
}
} else if (tt == TOK_LB) {
Node propExpr = expr(InAllowed, yieldHandling, TripledotProhibited);
Node propExpr = expr(InAllowed, yieldHandling, TripledotProhibited, possibleError);
if (!propExpr)
return null();
@ -9143,6 +9293,19 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
return lhs;
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling, TokenKind tt,
bool allowCallSyntax, InvokedPrediction invoked)
{
PossibleError possibleError(*this);
Node pn = memberExpr(yieldHandling, tripledotHandling, &possibleError, tt,
allowCallSyntax, invoked);
if (!pn || !possibleError.checkForExprErrors())
return null();
return pn;
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::newName(PropertyName* name)
@ -9515,13 +9678,15 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
return propName;
}
if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC)) {
if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) {
if (isGenerator) {
report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
return null();
}
tokenStream.ungetToken();
*propType = PropertyType::Shorthand;
*propType = tt == TOK_ASSIGN ?
PropertyType::CoverInitializedName :
PropertyType::Shorthand;
return propName;
}
@ -9562,7 +9727,7 @@ Parser<ParseHandler>::computedPropertyName(YieldHandling yieldHandling, Node lit
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling)
Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError* possibleError)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
@ -9571,6 +9736,7 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling)
return null();
bool seenPrototypeMutation = false;
bool seenCoverInitializedName = false;
RootedAtom propAtom(context);
for (;;) {
TokenKind tt;
@ -9629,6 +9795,43 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling)
if (!handler.addShorthand(literal, propName, nameExpr))
return null();
} else if (propType == PropertyType::CoverInitializedName) {
/*
* Support, e.g., |var {x=1, y=2} = o| as destructuring shorthand
* with default values, as per ES6 12.14.5 (2016/2/4)
*/
if (!tokenStream.checkForKeyword(propAtom, nullptr))
return null();
Node lhs = identifierName(yieldHandling);
if (!lhs)
return null();
tokenStream.consumeKnownToken(TOK_ASSIGN);
Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
if (!rhs)
return null();
Node propExpr = handler.newAssignment(PNK_ASSIGN, lhs, rhs, pc, JSOP_NOP);
if (!propExpr)
return null();
if (!handler.addPropertyDefinition(literal, propName, propExpr))
return null();
if (!abortIfSyntaxParser())
return null();
if (!seenCoverInitializedName) {
seenCoverInitializedName = true;
// "shorthand default" or "CoverInitializedName" syntax is only
// valid in the case of destructuring. Here we set a pending error so
// that later in the parse, once we've determined whether or not we're
// destructuring, the error can be reported or ignored appropriately.
if (possibleError)
possibleError->setPending(ParseError, JSMSG_BAD_PROP_ID, false);
}
} else {
// FIXME: Implement ES6 function "name" property semantics
// (bug 883377).
@ -9728,7 +9931,8 @@ Parser<ParseHandler>::tryNewTarget(Node &newTarget)
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling,
TokenKind tt, InvokedPrediction invoked)
PossibleError* possibleError, TokenKind tt,
InvokedPrediction invoked)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(tt));
JS_CHECK_RECURSION(context, return null());
@ -9744,7 +9948,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
return arrayInitializer(yieldHandling);
case TOK_LC:
return objectLiteral(yieldHandling);
return objectLiteral(yieldHandling, possibleError);
case TOK_LP: {
TokenKind next;
@ -9776,7 +9980,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
return generatorComprehension(begin);
}
Node expr = exprInParens(InAllowed, yieldHandling, TripledotAllowed);
Node expr = exprInParens(InAllowed, yieldHandling, TripledotAllowed, possibleError);
if (!expr)
return null();
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
@ -9880,6 +10084,16 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
}
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::exprInParens(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
PossibleError* possibleError)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LP));
return expr(inHandling, yieldHandling, tripledotHandling, possibleError, PredictInvoked);
}
// Legacy generator comprehensions can appear anywhere an expression is
// enclosed in parentheses, even if those parentheses are part of statement
// syntax or a function call:

View File

@ -364,6 +364,7 @@ enum PropListType { ObjectLiteral, ClassBody, DerivedClassBody };
enum class PropertyType {
Normal,
Shorthand,
CoverInitializedName,
Getter,
GetterNoExpressionClosure,
Setter,
@ -405,6 +406,72 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
operator StmtInfoPC*() { return &stmt_; }
};
/*
* A class for temporarily stashing errors while parsing continues.
*
* The ability to stash an error is useful for handling situations where we
* aren't able to verify that an error has occurred until later in the parse.
* For instance | ({x=1}) | is always parsed as an object literal with
* a SyntaxError, however, in the case where it is followed by '=>' we rewind
* and reparse it as a valid arrow function. Here a PossibleError would be
* set to 'pending' when the initial SyntaxError was encountered then 'resolved'
* just before rewinding the parser.
*
* When using PossibleError one should set a pending error at the location
* where an error occurs. From that point, the error may be resolved
* (invalidated) or left until the PossibleError is checked.
*
* Ex:
* PossibleError possibleError(*this);
* possibleError.setPending(ParseError, JSMSG_BAD_PROP_ID, false);
* // A JSMSG_BAD_PROP_ID ParseError is reported, returns false.
* possibleError.checkForExprErrors();
*
* PossibleError possibleError(*this);
* possibleError.setPending(ParseError, JSMSG_BAD_PROP_ID, false);
* possibleError.setResolved();
* // Returns true, no error is reported.
* possibleError.checkForExprErrors();
*
* PossibleError possibleError(*this);
* // Returns true, no error is reported.
* possibleError.checkForExprErrors();
*/
class MOZ_STACK_CLASS PossibleError
{
enum ErrorState { None, Pending };
ErrorState state_;
// Error reporting fields.
uint32_t offset_;
unsigned errorNumber_;
ParseReportKind reportKind_;
Parser<ParseHandler>& parser_;
bool strict_;
public:
explicit PossibleError(Parser<ParseHandler>& parser);
// Set a pending error.
void setPending(ParseReportKind kind, unsigned errorNumber, bool strict);
// Resolve any pending error.
void setResolved();
// Return true if an error is pending without reporting
bool hasError();
// If there is a pending error report it and return false, otherwise return
// true.
bool checkForExprErrors();
// Pass pending errors between possible error instances. This is useful
// for extending the lifetime of a pending error beyond the scope of
// the PossibleError where it was initially set (keeping in mind that
// PossibleError is a MOZ_STACK_CLASS).
void transferErrorTo(PossibleError* other);
};
public:
ExclusiveContext* const context;
LifoAlloc& alloc;
@ -754,7 +821,15 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
Node expr(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
PossibleError* possibleError,
InvokedPrediction invoked = PredictUninvoked);
Node expr(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
InvokedPrediction invoked = PredictUninvoked);
Node assignExpr(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
PossibleError* possibleError,
InvokedPrediction invoked = PredictUninvoked);
Node assignExpr(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
InvokedPrediction invoked = PredictUninvoked);
@ -762,16 +837,26 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
Node yieldExpression(InHandling inHandling);
Node condExpr1(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
PossibleError* possibleError,
InvokedPrediction invoked = PredictUninvoked);
Node orExpr1(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
InvokedPrediction invoked = PredictUninvoked);
PossibleError* possibleError,
InvokedPrediction invoked = PredictUninvoked);
Node unaryExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling,
PossibleError* possibleError,
InvokedPrediction invoked = PredictUninvoked);
Node memberExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling,
PossibleError* possibleError, TokenKind tt,
bool allowCallSyntax, InvokedPrediction invoked = PredictUninvoked);
Node memberExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling, TokenKind tt,
bool allowCallSyntax, InvokedPrediction invoked = PredictUninvoked);
Node primaryExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling, TokenKind tt,
Node primaryExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling,
PossibleError* possibleError, TokenKind tt,
InvokedPrediction invoked = PredictUninvoked);
Node exprInParens(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling,
PossibleError* possibleError);
Node exprInParens(InHandling inHandling, YieldHandling yieldHandling,
TripledotHandling tripledotHandling);
@ -848,7 +933,8 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
ForInOrOfTarget
};
bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor);
bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor,
PossibleError* possibleError=nullptr);
bool matchInOrOf(bool* isForInp, bool* isForOfp);
bool checkFunctionArguments();
@ -903,7 +989,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
Node arrayInitializer(YieldHandling yieldHandling);
Node newRegExp();
Node objectLiteral(YieldHandling yieldHandling);
Node objectLiteral(YieldHandling yieldHandling, PossibleError* possibleError);
enum PrepareLexicalKind {
PrepareLet,

View File

@ -1181,62 +1181,6 @@ function test_syntax(postfixes, check_error, ignore_opts) {
test("for each (let x in y ");
test("for each (let x in y) ");
// Legacy array comprehensions
test("[x ");
test("[x for ");
test("[x for ( ");
test("[x for (x ");
test("[x for (x of ");
test("[x for (x of y ");
test("[x for (x of y) ");
test("[x for (x of y) if ");
test("[x for (x of y) if ( ");
test("[x for (x of y) if (x ");
test("[x for (x of y) if (x == ");
test("[x for (x of y) if (x == 1 ");
test("[x for (x of y) if (x == 1) ");
test("[x for (x of y) if (x == 1)] ");
test("[x for (x in ");
test("[x for (x in y ");
test("[x for (x in y) ");
test("[x for each ");
test("[x for each ( ");
test("[x for each (x ");
test("[x for each (x in ");
test("[x for each (x in y ");
test("[x for each (x in y) ");
// Generator expressions
test("(x ");
test("(x for ");
test("(x for ( ");
test("(x for (x ");
test("(x for (x of ");
test("(x for (x of y ");
test("(x for (x of y) ");
test("(x for (x of y) if ");
test("(x for (x of y) if ( ");
test("(x for (x of y) if (x ");
test("(x for (x of y) if (x == ");
test("(x for (x of y) if (x == 1 ");
test("(x for (x of y) if (x == 1) ");
test("(x for (x of y) if (x == 1)) ");
test("(x for (x in ");
test("(x for (x in y ");
test("(x for (x in y) ");
test("(x for each ");
test("(x for each ( ");
test("(x for each (x ");
test("(x for each (x in ");
test("(x for each (x in y ");
test("(x for each (x in y) ");
// asm.js
test("(function() { 'use asm'; ");

View File

@ -1,4 +0,0 @@
function f1(g=((function () { return 4; }) for (x of [1]))) {
return g.next()();
}
assertEq(f1(), 4);

View File

@ -1,35 +1,41 @@
load(libdir + "asserts.js");
function f1(f=(function () { return typeof this !== "object"; })) { "use strict"; return f; }
eval(`"use strict";
function f1(f=(function () { return typeof this !== "object"; })) { return f; }
assertEq(f1()(), true);
`);
function f2(f=(function () { "use strict"; return (function () { return typeof this !== "object"; }) })) { assertEq(typeof this, "object"); return f; }
assertEq(f2()()(), true);
function f3(f=(function () { return (function () { return typeof this !== "object"; }) })) { "use strict"; return f; }
eval(`"use strict";
function f3(f=(function () { return (function () { return typeof this !== "object"; }) })) { return f; }
assertEq(f3()()(), true);
`);
// These should be okay.
function f4(f=(function () { with (Object) {} }), g=(function () { "use strict"; })) {}
function f5(g=(function () { "use strict"; }), f=(function () { with (Object) {} })) {}
function f6(f=(function () { return (x for (y in (function g() {}))); })) {}
assertThrowsInstanceOf(function () {
eval("function f(a=delete x) { 'use strict'; }");
eval("'use strict'; function f(a=delete x) { }");
}, SyntaxError);
assertThrowsInstanceOf(function () {
Math.sin(4);
eval("function f(a='\\251') { 'use strict'; }");
eval("'use strict'; function f(a='\\251') { }");
}, SyntaxError);
assertThrowsInstanceOf(function () {
eval("function f(a='\\251', b=delete x) { 'use strict'; }");
eval("'use strict'; function f(a='\\251', b=delete x) { }");
}, SyntaxError);
assertThrowsInstanceOf(function () {
eval("function f(a=delete x, b='\\251') { 'use strict'; }");
eval("'use strict'; function f(a=delete x, b='\\251') { }");
}, SyntaxError);
assertThrowsInstanceOf(function () {
eval("function f(a=(function () { '\\251'; })) { 'use strict'; }");
eval("'use strict'; function f(a=(function () { '\\251'; })) { }");
}, SyntaxError);
assertThrowsInstanceOf(function () {
eval("function f(a=(function () { with (Object) {} })) { 'use strict'; }");
eval("'use strict'; function f(a=(function () { with (Object) {} })) { }");
}, SyntaxError);
assertThrowsInstanceOf(function () {
eval("function f(a=(function (b, b) {})) { 'use strict'; }");
eval("'use strict'; function f(a=(function (b, b) {})) { }");
}, SyntaxError);

View File

@ -1,7 +0,0 @@
// No 'arguments' binding in genexprs at toplevel.
load(libdir + "asserts.js");
delete this.arguments; // it is defined in the shell
var iter = (arguments for (x of [1]));
assertThrowsInstanceOf(() => iter.next(), ReferenceError);

View File

@ -1,4 +0,0 @@
// 'arguments' is lexically scoped in genexprs at toplevel.
var arguments = 8;
assertEq((arguments for (x of [1])).next(), 8);

View File

@ -1,6 +0,0 @@
// 'arguments' is lexically scoped in genexpr in toplevel let-block.
{
let arguments = [];
assertEq((arguments for (p in {a: 1})).next(), arguments);
}

View File

@ -1,7 +0,0 @@
// 'arguments' is lexically scoped in genexpr in function.
function f() {
assertEq((arguments for (x of [0])).next(),
(arguments for (y of [1])).next());
}
f();

View File

@ -1,8 +0,0 @@
// 'arguments' binding can be closed over and outlives the function activation.
function f() {
return (arguments for (x of [1]));
}
var args = f("ponies").next();
assertEq(args[0], "ponies");

View File

@ -1,12 +0,0 @@
// 'arguments' works in nested genexprs.
function f() {
return ((((((arguments for (u of [0]))
for (v of [1]))
for (w of [2]))
for (x of [3]))
for (y of [4]))
for (z of [5]));
}
var args = f("ponies").next().next().next().next().next().next();
assertEq(args[0], "ponies");

View File

@ -1,13 +0,0 @@
// |jit-test| error:TypeError
// Binary: cache/js-dbg-32-86c8e18f20eb-linux
// Flags:
//
(function(){
for each (var x in new (
(function (){x})()
for each (y in [])
)
)
{const functional=undefined}
})()

View File

@ -1,4 +0,0 @@
// Binary: cache/js-dbg-64-55b6298ff619-linux
// Flags:
//
for(let x in []) {((x = [] for(x in [])) for(y in 0))}

View File

@ -1,9 +0,0 @@
// Binary: cache/js-dbg-32-b22e82ce2364-linux
// Flags: -j
//
x = (w for (x in []))
for (w in [0, 0, 0, 0]) {
(function() {
[c for (z in x)]
})()
}

View File

@ -1,11 +0,0 @@
// Binary: cache/js-dbg-32-e0fc487c23f4-linux
// Flags: -j
//
try {
for (window = (0
for (x in V)); f;) {}
} catch(e) {}
for each(let z in [0, 0, 0, 0, 0, 0, 0, 0, 0]) {
for (v in window) {}
}
var e, V

View File

@ -1,18 +0,0 @@
// Binary: cache/js-dbg-64-acf3c1fb7c94-linux
// Flags:
//
genexp = "x * x for (x in [])";
genexpParened = "(" + genexp + ")";
needParens(2, "if (1, xx) { }");
function needParens(section, pat, exp) {
ft = pat.replace(/xx/, genexpParened);
try {
f = new Function(ft);
} catch(e) { }
overParenTest(section, f, exp);
}
function overParenTest(section, f, exp) {
var uf = "" + f;
if (uf.indexOf(genexpParened) != -1) { }
}

View File

@ -1,6 +0,0 @@
// Binary: cache/js-dbg-64-defbe00ca091-linux
// Flags:
//
if (typeof disassemble == 'function') {
disassemble(eval(("(function(){(a for each (e in b));})")));
}

View File

@ -1,6 +0,0 @@
// Binary: cache/js-dbg-32-0f66a7ecf8de-linux
// Flags:
//
function n(b = ((function() {}), function() {
(a for (r in [function() {}]))
})) {}

View File

@ -1,10 +0,0 @@
Error.prototype.__proto__.p = 5;
f = Function("return( \"\" <arguments for(w in[]))");
for (i in f()) {}
(function() {
for (a in (
arguments for (l in [0])
))
{}
})()

View File

@ -1,10 +0,0 @@
// 'this' in generator-expression in strict-mode toplevel
// is the same as global 'this'.
"use strict";
var it1 = (this for (x of [0]));
assertEq(it1.next(), this);
var it2 = (this for (x of (this for (y of (this for (z of [0]))))));
assertEq(it2.next(), this);

View File

@ -1,11 +0,0 @@
// 'this' in escaping generator-expression in a method
// is the same as 'this' in the enclosing method.
var obj = {
f: function () {
assertEq(this, obj);
return (this for (x of [0]));
}
};
assertEq(obj.f().next(), obj);

View File

@ -1,11 +0,0 @@
// 'this' in escaping generator-expression in a method
// is the same as 'this' in the enclosing method
// even if the method does not otherwise use 'this'.
var obj = {
f: function () {
return (this for (x of [0]));
}
};
assertEq(obj.f().next(), obj);

View File

@ -1,13 +0,0 @@
// 'this' in a generator-expression non-strict function produces the expected
// object.
Number.prototype.iters = function () {
return [(this for (x of [0])),
(this for (y of [0]))];
};
var [a, b] = (3).iters();
var three = a.next();
assertEq(Object.prototype.toString.call(three), '[object Number]');
assertEq(+three, 3);
assertEq(b.next(), three);

View File

@ -1,13 +0,0 @@
a = (function() {
with({}) var x, arguments, arguments
})()
b = (function() {
with({}) {
var x = Math, arguments
({
get: (1 for (x in [])),
})
}
})()

View File

@ -4,6 +4,7 @@ load(libdir + 'eqArrayHelper.js');
var arrayPattern = '[a = 1, b = 2, c = 3, d = 4, e = 5, f = 6]';
var objectPattern = '{0: a = 1, 1: b = 2, 2: c = 3, 3: d = 4, 4: e = 5, 5: f = 6}';
var objectPatternShorthand = '{a = 1, b = 2, c = 3, d = 4, e = 5, f = 6}';
var nestedPattern = '{a: a = 1, b: [b = 2] = [], c: {c: [c]} = {c: [3]}, d: {d, e} = {d: 4, e: 5}, f: f = 6}';
function testAll(fn) {
@ -17,6 +18,11 @@ function testAll(fn) {
assertEqArray(fn(objectPattern, [undefined, 0, false, null, "", undefined]), [1, 0, false, null, "", 6]);
assertEqArray(fn(objectPattern, [0, false]), [0, false, 3, 4, 5, 6]);
assertEqArray(fn(objectPatternShorthand, {}), [1, 2, 3, 4, 5, 6]);
assertEqArray(fn(objectPatternShorthand, {a: 2, b: 3, c: 4, d: 5, e: 6, f: 7, g: 8, h: 9}), [2, 3, 4, 5, 6, 7]);
assertEqArray(fn(objectPatternShorthand, {a: undefined, b: 0, c: false, d: null, e: "", f: undefined}),
[1, 0, false, null, "", 6]);
assertEqArray(fn(objectPatternShorthand, {a: 0, b: false}), [0, false, 3, 4, 5, 6]);
assertEqArray(fn(nestedPattern, {}), [1, 2, 3, 4, 5, 6]);
assertEqArray(fn(nestedPattern, {a: 2, b: [], c: undefined}), [2, 2, 3, 4, 5, 6]);
assertEqArray(fn(nestedPattern, {a: undefined, b: [3], c: {c: [4]}}), [1, 3, 4, 4, 5, 6]);
@ -175,5 +181,9 @@ if (defaultsSupportedInForVar) {
b = undefined;
for (let {1: c = 10} in " ") { b = c; }
assertEq(b, 10);
b = undefined;
for (let {c = 10} in " ") { b = c; }
assertEq(b, 10);
`)();
}

View File

@ -1,7 +0,0 @@
function getgen() {
gen = getgen.caller;
}
var gen;
(getgen() for (x of [1])).next();
assertEq(gen.toSource(), "function genexp() {\n [generator expression]\n}");
assertEq(gen.toString(), gen.toSource());

View File

@ -1,6 +0,0 @@
function outer() {
(function() {x})
assertEq(((function() {return x}) for (x in [42])).next()(), "0");
var x;
}
outer();

View File

@ -1,8 +0,0 @@
var g = newGlobal();
var dbg = new g.Debugger(this);
try {
function f() {}
(1 for (x in []))
} catch (e) {}
gc()

View File

@ -1,5 +0,0 @@
assertEq(((function() arguments) for (x in [1])).next()(42)[0], 42);
assertEq(((function() {return arguments}) for (x in [1])).next()(42)[0], 42);
assertEq(((function() {return arguments[0] + arguments[1]}) for (x in [1])).next()(41,1), 42);
assertEq(((function() {return arguments[0] + (function() { return arguments[0]})(arguments[1])}) for (x in [1])).next()(41,1), 42);
assertEq(((function() { var arguments = 3; return arguments}) for (x in [1])).next()(42), 3);

View File

@ -179,6 +179,7 @@ isParseError('for (let [x, y, x] in o) {}');
isParseError('for (let [x, [y, [x]]] in o) {}');
// for(let ... in ...) scoping bugs (bug 1069480)
// XXX: ES6 now requires these to be ReferenceErrors; see the test from ESR52.
test('for each (let [x, y] in x) {return x + y;}', [['ponies', '']], undefined);
test('for each (let [{0: x, 1: y}, z] in x) {return x + y + z;}', [[['po','nies'], '']], undefined);
test('for (let x in eval("x")) {return x;}', {ponies:true}, undefined);
@ -190,18 +191,6 @@ test('try {for (let x in eval("throw x")) {}} catch (e) {return e;}', undefined,
test('try {for each (let x in x) {eval("throw x");}} catch (e) {return e;}', ['ponies'], undefined);
test('for each (let {x: y, y: x} in [{x: x, y: x}]) {return y;}', undefined, undefined);
// genexps
test('return (i for (i in x)).next();', {ponies:true});
test('return (eval("i") for (i in x)).next();', {ponies:true});
test('return (eval("i") for (i in eval("x"))).next();', {ponies:true});
test('try {return (eval("throw i") for (i in x)).next();} catch (e) {return e;}', {ponies:true});
// array comprehension
test('return [i for (i in x)][0];', {ponies:true});
test('return [eval("i") for (i in x)][0];', {ponies:true});
test('return [eval("i") for (i in eval("x"))][0];', {ponies:true});
test('try {return [eval("throw i") for (i in x)][0];} catch (e) {return e;}', {ponies:true});
// don't forget about switch craziness
test('var y = 3;switch (function () {return eval("y");}()) {case 3:let y;return x;default:;}');
test('switch (x) {case 3:let y;return 3;case 4:let z;return 4;default:return x;}');

View File

@ -21,14 +21,6 @@ test("for (let x in h()) ;", 'declarative');
test("for (let x in {a:1}) h();", 'declarative');
test("try { throw new Error; } catch (x) { h(x) }", 'declarative');
test("'use strict'; eval('var z = 1; h();');", 'declarative');
test("for (var x in [h(m) for (m in [1])]) ;", 'declarative');
test("for (var x in (h(m) for (m in [1]))) ;", 'declarative');
// Since a generator-expression is effectively a function, the innermost scope
// is a function scope, and thus declarative. Thanks to an odd design decision,
// m is already in scope at the point of the call to h(). The answer here is
// not all that important, but we shouldn't crash.
test("for (var x in (0 for (m in h()))) ;", 'declarative');
dbg.onDebuggerStatement = function (frame) {
assertEq(frame.eval("h(), 2 + 2;").return, 4);

View File

@ -40,5 +40,3 @@ test("function r(n) { for (var i = 0; i < n; i++) yield i; } debugger;",
"S[S]");
test("function* qux(n) { for (var i = 0; i < n; i++) yield i; } debugger;",
"S[S]");
test("var it = (3 for (p in obj)); debugger;",
"S[S]");

View File

@ -52,9 +52,6 @@ test(function () { g.eval("function r(n) { for (var i=0;i<n;i++) yield i; }"); }
// eval declaring a star generator
test(function () { g.eval("function* sg(n) { for (var i=0;i<n;i++) yield i; }"); });
// eval with a generator-expression
test(function () { g.eval("var it = (obj[p] for (p in obj));"); });
// eval creating several instances of a closure
test(function () { g.eval("for (var i = 0; i < 7; i++)\n" +
" obj = function () { return obj; };\n"); });

View File

@ -26,11 +26,3 @@ test("for ([a, b] of c) { a.m(b); }");
// for-let-of
test("for (let a of b) { f(a); }");
test("for (let [a, b] of c) { a.m(b); }");
// array comprehensions
test("return [a for (a of b)];");
test("return [[b, a] for ([a, b] of c.items())];");
// generator expressions
test("return (a for (a of b));");

View File

@ -1,15 +0,0 @@
// for-of can iterate over generator-iterators produced by generator-expressions.
function g() {
yield 1;
yield 2;
}
var it = g();
for (var i = 0; i < 10; i++) {
let prev = it;
it = (k + 1 for (k of prev));
}
var arr = [v for (v of it)];
assertEq(arr.join(), "11,12");

View File

@ -1,15 +0,0 @@
// |jit-test| error: TypeError
x = 2;
function tryItOut(c) {
return eval("(function(){" + c + "})");
}
function doit() {
var f = tryItOut("((( \"\" \n for each (eval in [null, this, null, this, (1/0), new String('q'), new String('q'), null, null, null, new String('q'), new String('q'), new String('q'), null]) if (this)).eval(x = x)));");
f();
}
doit();

View File

@ -0,0 +1,13 @@
function
request(endpoint, {
httpMethod = 'GET',
params = {},
resultAs = 'json',
data = {}
} = {}) {
return resultAs;
}
assertEq(request(), "json");
assertEq(request(null, { httpMethod: 'POST' }), "json");
assertEq(request(null, { resultAs: 'xml' }), "xml");

View File

@ -0,0 +1,9 @@
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen(); // "Generator { }"
assertEq(g.next().value, 1);
assertEq(g.next().value, 2);

View File

@ -0,0 +1,102 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
// Ensure that the syntax used in shorthand destructuring with defaults
// e.g. |{x=1, y=2} = {}| properly raises a syntax error within an object
// literal. As per ES6 12.2.6 Object Initializer, "NOTE 3."
const SYNTAX_ERROR_STMTS = [
// expressions
"({x={}={}}),",
"({y={x={}={}={}={}={}={}={}={}}={}}),",
"({a=1, b=2, c=3, x=({}={})}),",
"({x=1, y={z={1}}})",
"({x=1} = {y=1});",
"({x: y={z=1}}={})",
"({x=1}),",
"({z=1}={}, {w=2}, {e=3})=>{};",
"({z={x=1}})=>{};",
"({x = ({y=1}) => y})",
"(({x=1})) => x",
// declarations
"let o = {x=1};",
"var j = {x=1};",
"var j = {x={y=1}}={};",
"const z = {x=1};",
"const z = {x={y=1}}={};",
"const {x=1};",
"const {x={y=33}}={};",
"var {x=1};",
"let {x=1};",
"let x, y, {z=1}={}, {w=2}, {e=3};",
// array initialization
"[{x=1, y = ({z=2} = {})}];",
// try/catch
"try {throw 'a';} catch ({x={y=1}}) {}",
// if/else
"if ({k: 1, x={y=2}={}}) {}",
"if (false) {} else if (true) { ({x=1}) }",
// switch
"switch ('c') { case 'c': ({x=1}); }",
// for
"for ({x=1}; 1;) {1}",
"for ({x={y=2}}; 1;) {1}",
"for (var x = 0; x < 2; x++) { ({x=1, y=2}) }",
"for (let x=1;{x=1};){}",
"for (let x=1;{x={y=2}};){}",
"for (let x=1;1;{x=1}){}",
"for (let x=1;1;{x={y=2}}){}",
// while
"while ({x=1}) {1};",
"while ({x={y=2}}={}) {1};",
// with
"with ({x=1}) {};",
"with ({x={y=3}={}}) {};",
"with (Math) { ({x=1}) };"
]
for (var stmt of SYNTAX_ERROR_STMTS) {
assertThrowsInstanceOf(() => {
eval(stmt);
}, SyntaxError);
}
const REFERENCE_ERROR_STMTS = [
"({x} += {});",
"({x = 1}) = {x: 2};",
]
for (var stmt of REFERENCE_ERROR_STMTS) {
assertThrowsInstanceOf(() => {
eval(stmt);
}, ReferenceError);
}
// A few tricky but acceptable cases:
// see https://bugzilla.mozilla.org/show_bug.cgi?id=932080#c2
assertEq((({a = 0}) => a)({}), 0);
assertEq((({a = 0} = {}) => a)({}), 0);
assertEq((({a = 0} = {}) => a)({a: 1}), 1);
{
let x, y;
({x=1} = {});
assertEq(x, 1);
({x=1} = {x: 4});
assertEq(x, 4);
({x=1, y=2} = {})
assertEq(x, 1);
assertEq(y, 2);
}
{
let {x={i=1, j=2}={}}={};
assertDeepEq(x, ({}));
assertEq(i, 1);
assertEq(j, 2);
}
if (typeof reportCompare == "function")
reportCompare(true, true);

View File

@ -1,27 +0,0 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
* Contributor:
* Jeff Walden <jwalden+code@mit.edu>
*/
//-----------------------------------------------------------------------------
var BUGNUMBER = 721322;
var summary = 'Allow f.arguments in generator expressions';
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
eval("(function() { return (f.arguments for (x in [1])); })()");
eval("(function() { var f = { arguments: 12 }; return [f.arguments for (x in [1])]; })()");
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

View File

@ -1,30 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 380237;
var summary = 'Decompilation of generator expressions';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
var f = function() { g = (d for (d in [0])); g.next(); };
expect = 'function() { g = (d for (d in [0])); g.next(); }';
actual = f + '';
compareSource(expect, actual, summary);
exitFunc ('test');
}

View File

@ -1,51 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
* Contributor: Jason Orendorff
*/
//-----------------------------------------------------------------------------
var BUGNUMBER = 452498;
var summary = 'TM: upvar2 regression tests';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
// ------- Comment #52 From Jason Orendorff
// Crash in NoteLValue, called from BindDestructuringVar.
// NoteLValue assumes pn->pn_lexdef is non-null, but here
// pn is itself the definition of x.
for (var [x] in null) ;
// This one only crashes when executed from a file.
// Assertion failure: pn != dn->dn_uses, at ../jsparse.cpp:1131
for (var f in null)
;
var f = 1;
(f)
// Assertion failure: pnu->pn_cookie == FREE_UPVAR_COOKIE, at ../jsemit.cpp:1815
// In EmitEnterBlock. x has one use, which is pnu here.
// pnu is indeed a name, but pnu->pn_cookie is 0.
try { eval('let (x = 1) { var x; }'); } catch(ex) {}
// Assertion failure: cg->upvars.lookup(atom), at ../jsemit.cpp:1992
// atom="x", upvars is empty.
(1 for each (x in x));
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -1,69 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 452498;
var summary = 'TM: upvar2 regression tests';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
// =====
foo = "" + new Function("while(\u3056){let \u3056 = x}");
// =====
function a(){ let c; eval("let c, y"); }
a();
// =====
try
{
{x: 1e+81 ? c : arguments}
}
catch(ex)
{
}
// =====
(function(q){return q;} for each (\u3056 in []))
// =====
function f(){ var c; eval("{var c = NaN, c;}"); }
f();
// =====
try
{
eval(
' x\n' +
' let(x) {\n' +
' var x\n'
);
}
catch(ex)
{
}
// =====
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -44,34 +44,6 @@ function test()
}
g("for (var x = 0; x < 3; ++x)(new (function(){})());");
// =====
try
{
(function(){new (function ({}, x) { yield (x(1e-81) for (x4 in undefined)) })()})();
}
catch(ex)
{
}
// =====
try
{
(function(){[(function ([y]) { })() for each (x in [])];})();
}
catch(ex)
{
}
// =====
try
{
eval('(function(){for(var x2 = [function(id) { return id } for each (x in []) if ([])] in functional) function(){};})();');
}
catch(ex)
{
}
// =====
try
{
@ -104,21 +76,6 @@ function test()
var f = new Function("[] = [( '' )()];");
"" + f;
// =====
try
{
eval(
'for(let x;' +
' ([,,,]' +
' .toExponential(new Function(), (function(){}))); [] = {})' +
' for(var [x, x] = * in this.__defineSetter__("", function(){}));'
);
}
catch(ex)
{
}
// =====
reportCompare(expect, actual, summary);

View File

@ -1,31 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 452498;
var summary = 'TM: upvar2 regression tests';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
// ------- Comment #98 From Gary Kwong [:nth10sd]
uneval(function(){(Number(0) for each (NaN in []) for each (x4 in this))});
// Assertion failure: pos == 0, at ../jsopcode.cpp:2963
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -1,54 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 452498;
var summary = 'TM: upvar2 regression tests';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
// ------- Comment #99 From Gary Kwong [:nth10sd]
try
{
eval("(function x(){x.(this)} )();");
}
catch(ex)
{
}
// Assertion failure: (uint32_t)(index_) < atoms_->length, at ../jsinterp.cpp:327
// Crash [@ js_FullTestPropertyCache] at null in opt, -j not required.
// =====
try
{
(function(){try {x} finally {}; ([x in []] for each (x in x))})();
}
catch(ex)
{
}
// Assertion failure: lexdep->frameLevel() <= funbox->level, at ../jsparse.cpp:1735
// Crash [@ BindNameToSlot] near null in opt, -j not required.
// =====
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -55,24 +55,6 @@ function test()
}
// Assertion failure: regs.sp == StackBase(fp), at ../jsinterp.cpp:2984
// =====
try
{
do {x} while([[] for (x in []) ]);
}
catch(ex)
{
}
// Assertion failure: !(pnu->pn_dflags & PND_BOUND), at ../jsemit.cpp:1818
// =====
try
{
{x} ((x=[] for (x in []))); x;
}
catch(ex)
{
}
// Assertion failure: cg->staticLevel >= level, at ../jsemit.cpp:2014
// Crash [@ BindNameToSlot] in opt without -j

View File

@ -1,43 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 452498;
var summary = 'TM: upvar2 regression tests';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
// ------- Comment #130 From Gary Kwong [:nth10sd]
// Does not require -j:
// =====
((function x()x in []) for (y in []))
// Assertion failure: !(pnu->pn_dflags & PND_BOUND), at ../jsemit.cpp:1818
// =====
// Requires -j:
// =====
for (var x = 0; x < 3; ++x) { new function(){} }
// Assertion failure: cx->bailExit, at ../jstracer.cpp:4672
// Opt crash [@ LeaveTree] near null
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -32,34 +32,6 @@ function test()
}
}
// Assertion failure: fp2->fun && fp2->script, at ../jsinterp.cpp:5633
// Opt crash [@ js_Interpret]
// ===
try
{
(x for each (c in []))
x
}
catch(ex)
{
}
// Assertion failure: ss->printer->pcstack, at ../jsopcode.cpp:909
// ===
try
{
(function(){for(; (this); ((window for (x in [])) for (y in []))) 0});
}
catch(ex)
{
}
// Assertion failure: level >= tc->staticLevel, at ../jsparse.cpp:5773
// ===
eval(uneval( function(){
((function()y)() for each (x in this))
} ))
// Debug & opt crash [@ BindNameToSlot]
// -j is required:

View File

@ -1,44 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 452498;
var summary = 'TM: upvar2 regression tests';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
// ------- Comment #138 From Gary Kwong [:nth10sd]
// Does not require -j:
// ===
((function x(){ yield (x = undefined) } ) for (y in /x/));
// Assertion failure: lexdep->frameLevel() <= funbox->level, at ../jsparse.cpp:1820
// ===
try
{
for(let x in ( x for (y in x) for each (x in []) )) y;
}
catch(ex)
{
}
// Assertion failure: cg->upvars.lookup(atom), at ../jsemit.cpp:2034
// ===
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -1,35 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 507424;
var summary = 'TM: assert with regexp literal inside closure'
var actual = '';
var expect = 'do not crash';
//-----------------------------------------------------------------------------
start_test();
jit(true);
(new Function("'a'.replace(/a/,function(x){return(/x/ for each(y in[x]))})"))();
jit(false);
actual = 'do not crash'
finish_test();
//-----------------------------------------------------------------------------
function start_test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
}
function finish_test()
{
reportCompare(expect, actual, summary);
exitFunc ('test');
}

View File

@ -1,6 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
var it = (x for (x in [function(){}]));
it.next();
reportCompare("no assertion failure", "no assertion failure", "See bug 515885.");

View File

@ -1,38 +0,0 @@
// |reftest| skip-if(Android)
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
/*
* In strict mode, generator expressions may not locally bind 'eval'
* or 'arguments.'
*/
assertEq(testLenientAndStrict('(1 for (eval in []))',
parsesSuccessfully,
parseRaisesException(SyntaxError)),
true);
assertEq(testLenientAndStrict('(1 for ([eval] in []))',
parsesSuccessfully,
parseRaisesException(SyntaxError)),
true);
assertEq(testLenientAndStrict('(1 for ({x:eval} in []))',
parsesSuccessfully,
parseRaisesException(SyntaxError)),
true);
assertEq(testLenientAndStrict('(1 for (arguments in []))',
parsesSuccessfully,
parseRaisesException(SyntaxError)),
true);
assertEq(testLenientAndStrict('(1 for ([arguments] in []))',
parsesSuccessfully,
parseRaisesException(SyntaxError)),
true);
assertEq(testLenientAndStrict('(1 for ({x:arguments} in []))',
parsesSuccessfully,
parseRaisesException(SyntaxError)),
true);
reportCompare(true, true);

View File

@ -1,23 +0,0 @@
// -*- indent-tabs-mode: nil; js-indent-level: 4 -*-
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
var x = 42;
function a() {
var x;
function b() {
x = 43;
// When jsparse.cpp's CompExprTransplanter transplants the
// comprehension expression 'x' into the scope of the 'for' loop,
// it must not bring the placeholder definition node for the
// assignment to x above along with it. If it does, x won't appear
// in b's lexdeps, we'll never find out that the assignment refers
// to a's x, and we'll generate an assignment to the global x.
(x for (x in []));
}
b();
}
a();
assertEq(x, 42);
reportCompare(true, true);

View File

@ -39,8 +39,6 @@ assertGlobalExpr("(function() { })", 11, { functionExpression: () => 11 });
assertGlobalExpr("[1,2,3]", 12, { arrayExpression: () => 12 });
assertGlobalExpr("({ x: y })", 13, { objectExpression: () => 13 });
assertGlobalExpr("this", 14, { thisExpression: () => 14 });
assertGlobalExpr("[x for (x in y)]", 17, { comprehensionExpression: () => 17 });
assertGlobalExpr("(x for (x in y))", 18, { generatorExpression: () => 18 });
assertGlobalExpr("(function() { yield 42 })", genFunExpr("legacy", null, [], blockStmt([exprStmt(19)])), { yieldExpression: () => 19 });
assertGlobalStmt("switch (x) { case y: }", switchStmt(ident("x"), [1]), { switchCase: () => 1 });
@ -50,9 +48,6 @@ assertGlobalStmt("try { } catch (e) { }", tryStmt(blockStmt([]), [], 2, null), {
assertGlobalStmt("try { } catch (e if e instanceof A) { } catch (e if e instanceof B) { }",
tryStmt(blockStmt([]), [2, 2], null, null),
{ catchClause: () => 2 });
assertGlobalExpr("[x for (y in z) for (x in y)]",
compExpr(ident("x"), [3, 3], null, "legacy"),
{ comprehensionBlock: () => 3 });
assertGlobalExpr("({ x: y } = z)", aExpr("=", 1, ident("z")), { objectPattern: () => 1 });
assertGlobalExpr("({ x: y } = z)", aExpr("=", objPatt([2]), ident("z")), { propertyPattern: () => 2 });

View File

@ -1,79 +1,33 @@
// |reftest| skip-if(!xulRuntime.shell)
function test() {
// generator expressions
assertExpr("( x for (x in foo))",
genExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], null, "legacy"));
assertExpr("( [x,y] for (x in foo) for (y in bar))",
genExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], null, "legacy"));
assertExpr("( [x,y,z] for (x in foo) for (y in bar) for (z in baz))",
genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
[compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
null,
"legacy"));
assertExpr("( x for (x in foo) if (p))",
genExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], ident("p"), "legacy"));
assertExpr("( [x,y] for (x in foo) for (y in bar) if (p))",
genExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], ident("p"), "legacy"));
assertExpr("( [x,y,z] for (x in foo) for (y in bar) for (z in baz) if (p) )",
genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
[compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
ident("p"),
"legacy"));
assertExpr("( x for each (x in foo))",
genExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], null, "legacy"));
assertExpr("( [x,y] for each (x in foo) for each (y in bar))",
genExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], null, "legacy"));
assertExpr("( [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz))",
genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
[compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
null,
"legacy"));
assertExpr("( x for each (x in foo) if (p))",
genExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], ident("p"), "legacy"));
assertExpr("( [x,y] for each (x in foo) for each (y in bar) if (p))",
genExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], ident("p"), "legacy"));
assertExpr("( [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz) if (p) )",
genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
[compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
ident("p"),
"legacy"));
// Generator expressions using for-of can be written in two different styles.
function assertLegacyAndModernGenExpr(expr, body, blocks, filter) {
assertExpr(expr, genExpr(body, blocks, filter, "legacy"));
// Transform the legacy genexpr to a modern genexpr and test it that way
// too.
// Translate legacy genexprs into less legacy genexprs and test them.
function assertFormerlyES6GenExpr(expr, body, blocks, filter) {
let match = expr.match(/^\((.*?) for (.*)\)$/);
assertEq(match !== null, true);
let expr2 = "(for " + match[2] + " " + match[1] + ")";
assertExpr(expr2, genExpr(body, blocks, filter, "modern"));
}
assertLegacyAndModernGenExpr("( x for (x of foo))",
ident("x"), [compOfBlock(ident("x"), ident("foo"))], null);
assertLegacyAndModernGenExpr("( [x,y] for (x of foo) for (y of bar))",
arrExpr([ident("x"), ident("y")]), [compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar"))], null);
assertLegacyAndModernGenExpr("( [x,y,z] for (x of foo) for (y of bar) for (z of baz))",
arrExpr([ident("x"), ident("y"), ident("z")]),
[compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar")), compOfBlock(ident("z"), ident("baz"))],
null);
assertFormerlyES6GenExpr("( x for (x of foo))",
ident("x"), [compOfBlock(ident("x"), ident("foo"))], null);
assertFormerlyES6GenExpr("( [x,y] for (x of foo) for (y of bar))",
arrExpr([ident("x"), ident("y")]), [compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar"))], null);
assertFormerlyES6GenExpr("( [x,y,z] for (x of foo) for (y of bar) for (z of baz))",
arrExpr([ident("x"), ident("y"), ident("z")]),
[compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar")), compOfBlock(ident("z"), ident("baz"))],
null);
assertLegacyAndModernGenExpr("( x for (x of foo) if (p))",
ident("x"), [compOfBlock(ident("x"), ident("foo"))], ident("p"));
assertLegacyAndModernGenExpr("( [x,y] for (x of foo) for (y of bar) if (p))",
arrExpr([ident("x"), ident("y")]), [compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar"))], ident("p"));
assertLegacyAndModernGenExpr("( [x,y,z] for (x of foo) for (y of bar) for (z of baz) if (p) )",
arrExpr([ident("x"), ident("y"), ident("z")]),
[compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar")), compOfBlock(ident("z"), ident("baz"))],
ident("p"));
assertFormerlyES6GenExpr("( x for (x of foo) if (p))",
ident("x"), [compOfBlock(ident("x"), ident("foo"))], ident("p"));
assertFormerlyES6GenExpr("( [x,y] for (x of foo) for (y of bar) if (p))",
arrExpr([ident("x"), ident("y")]), [compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar"))], ident("p"));
assertFormerlyES6GenExpr("( [x,y,z] for (x of foo) for (y of bar) for (z of baz) if (p) )",
arrExpr([ident("x"), ident("y"), ident("z")]),
[compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar")), compOfBlock(ident("z"), ident("baz"))],
ident("p"));
// Modern generator comprehension with multiple ComprehensionIf.
// FormerlyES6 generator comprehension with multiple ComprehensionIf.
assertExpr("(for (x of foo) x)",
genExpr(ident("x"), [compOfBlock(ident("x"), ident("foo"))], null, "modern"));

View File

@ -1,19 +0,0 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
/* Don't crash. */
try {
eval("function f(){}(((f)for(x in function(){}))())");
var threwTypeError = false;
} catch (x) {
var threwTypeError = x instanceof TypeError;
}
assertEq(threwTypeError, true);
/* Properly bind f. */
assertEq(eval("function f() {}; var i = (f for (f in [1])); uneval([n for (n in i)])"),
'["0"]');
reportCompare(true, true);

View File

@ -1,19 +0,0 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
var expect = true;
var actual = expect;
function f() {
'use strict';
for (; false; (0 for each (t in eval("")))) { }
}
fs = "" + f;
try {
eval("(" + fs + ")");
} catch (e) {
actual = false;
}
reportCompare(expect, actual, "ok");