1303703 - Syntax parse destructuring patterns.
parent
713888bd05
commit
d7a91d9be2
|
@ -878,6 +878,10 @@ class FullParseHandler
|
|||
return node->isKind(PNK_NAME);
|
||||
}
|
||||
|
||||
bool isArgumentsAnyParentheses(ParseNode* node, ExclusiveContext* cx) {
|
||||
return node->isKind(PNK_NAME) && node->pn_atom == cx->names().arguments;
|
||||
}
|
||||
|
||||
bool isEvalAnyParentheses(ParseNode* node, ExclusiveContext* cx) {
|
||||
return node->isKind(PNK_NAME) && node->pn_atom == cx->names().eval;
|
||||
}
|
||||
|
@ -888,7 +892,7 @@ class FullParseHandler
|
|||
|
||||
if (isEvalAnyParentheses(node, cx))
|
||||
return js_eval_str;
|
||||
if (node->pn_atom == cx->names().arguments)
|
||||
if (isArgumentsAnyParentheses(node, cx))
|
||||
return js_arguments_str;
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -689,6 +689,19 @@ ParserBase::extraWarning(unsigned errorNumber, ...)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
ParserBase::extraWarningAt(uint32_t offset, unsigned errorNumber, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, errorNumber);
|
||||
|
||||
bool result =
|
||||
tokenStream.reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, args);
|
||||
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
ParserBase::strictModeError(unsigned errorNumber, ...)
|
||||
{
|
||||
|
@ -743,14 +756,6 @@ ParserBase::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumb
|
|||
return result;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<FullParseHandler>::abortIfSyntaxParser()
|
||||
{
|
||||
handler.disableSyntaxParser();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<SyntaxParseHandler>::abortIfSyntaxParser()
|
||||
|
@ -4128,8 +4133,17 @@ Parser<ParseHandler>::PossibleError::error(ErrorKind kind)
|
|||
{
|
||||
if (kind == ErrorKind::Expression)
|
||||
return exprError_;
|
||||
MOZ_ASSERT(kind == ErrorKind::Destructuring);
|
||||
return destructuringError_;
|
||||
if (kind == ErrorKind::Destructuring)
|
||||
return destructuringError_;
|
||||
MOZ_ASSERT(kind == ErrorKind::DestructuringWarning);
|
||||
return destructuringWarning_;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::PossibleError::hasPendingDestructuringError()
|
||||
{
|
||||
return hasError(ErrorKind::Destructuring);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
|
@ -4171,6 +4185,14 @@ Parser<ParseHandler>::PossibleError::setPendingDestructuringErrorAt(const TokenP
|
|||
setPending(ErrorKind::Destructuring, pos, errorNumber);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
void
|
||||
Parser<ParseHandler>::PossibleError::setPendingDestructuringWarningAt(const TokenPos& pos,
|
||||
unsigned errorNumber)
|
||||
{
|
||||
setPending(ErrorKind::DestructuringWarning, pos, errorNumber);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
void
|
||||
Parser<ParseHandler>::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos,
|
||||
|
@ -4193,23 +4215,36 @@ Parser<ParseHandler>::PossibleError::checkForError(ErrorKind kind)
|
|||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::PossibleError::checkForDestructuringError()
|
||||
Parser<ParseHandler>::PossibleError::checkForWarning(ErrorKind kind)
|
||||
{
|
||||
if (!hasError(kind))
|
||||
return true;
|
||||
|
||||
Error& err = error(kind);
|
||||
return parser_.extraWarningAt(err.offset_, err.errorNumber_);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::PossibleError::checkForDestructuringErrorOrWarning()
|
||||
{
|
||||
// Clear pending expression error, because we're definitely not in an
|
||||
// expression context.
|
||||
setResolved(ErrorKind::Expression);
|
||||
|
||||
// Report any pending destructuring error.
|
||||
return checkForError(ErrorKind::Destructuring);
|
||||
// Report any pending destructuring error or warning.
|
||||
return checkForError(ErrorKind::Destructuring) &&
|
||||
checkForWarning(ErrorKind::DestructuringWarning);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::PossibleError::checkForExpressionError()
|
||||
{
|
||||
// Clear pending destructuring error, because we're definitely not in a
|
||||
// destructuring context.
|
||||
// Clear pending destructuring error or warning, because we're definitely
|
||||
// not in a destructuring context.
|
||||
setResolved(ErrorKind::Destructuring);
|
||||
setResolved(ErrorKind::DestructuringWarning);
|
||||
|
||||
// Report any pending expression error.
|
||||
return checkForError(ErrorKind::Expression);
|
||||
|
@ -4241,192 +4276,258 @@ Parser<ParseHandler>::PossibleError::transferErrorsTo(PossibleError* other)
|
|||
transferErrorTo(ErrorKind::Expression, other);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<FullParseHandler>::checkDestructuringName(ParseNode* expr, Maybe<DeclarationKind> maybeDecl)
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::bindingInitializer(Node lhs, DeclarationKind kind,
|
||||
YieldHandling yieldHandling)
|
||||
{
|
||||
MOZ_ASSERT(!handler.isUnparenthesizedDestructuringPattern(expr));
|
||||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_ASSIGN));
|
||||
|
||||
// Parentheses are forbidden around destructuring *patterns* (but allowed
|
||||
// around names). Use our nicer error message for parenthesized, nested
|
||||
// patterns.
|
||||
if (handler.isParenthesizedDestructuringPattern(expr)) {
|
||||
errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_PARENS);
|
||||
return false;
|
||||
if (kind == DeclarationKind::FormalParameter)
|
||||
pc->functionBox()->hasParameterExprs = true;
|
||||
|
||||
Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
|
||||
if (!rhs)
|
||||
return null();
|
||||
|
||||
handler.checkAndSetIsDirectRHSAnonFunction(rhs);
|
||||
|
||||
Node assign = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP);
|
||||
if (!assign)
|
||||
return null();
|
||||
|
||||
if (foldConstants && !FoldConstants(context, &assign, this))
|
||||
return null();
|
||||
|
||||
return assign;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::bindingIdentifier(DeclarationKind kind, YieldHandling yieldHandling)
|
||||
{
|
||||
RootedPropertyName name(context, bindingIdentifier(yieldHandling));
|
||||
if (!name)
|
||||
return null();
|
||||
|
||||
Node binding = newName(name);
|
||||
if (!binding || !noteDeclaredName(name, kind, pos()))
|
||||
return null();
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::bindingIdentifierOrPattern(DeclarationKind kind, YieldHandling yieldHandling,
|
||||
TokenKind tt)
|
||||
{
|
||||
if (tt == TOK_LB)
|
||||
return arrayBindingPattern(kind, yieldHandling);
|
||||
|
||||
if (tt == TOK_LC)
|
||||
return objectBindingPattern(kind, yieldHandling);
|
||||
|
||||
if (!TokenKindIsPossibleIdentifierName(tt)) {
|
||||
error(JSMSG_NO_VARIABLE_NAME);
|
||||
return null();
|
||||
}
|
||||
|
||||
// This expression might be in a variable-binding pattern where only plain,
|
||||
// unparenthesized names are permitted.
|
||||
if (maybeDecl) {
|
||||
// Destructuring patterns in declarations must only contain
|
||||
// unparenthesized names.
|
||||
if (!handler.isUnparenthesizedName(expr)) {
|
||||
errorAt(expr->pn_pos.begin, JSMSG_NO_VARIABLE_NAME);
|
||||
return false;
|
||||
return bindingIdentifier(kind, yieldHandling);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling)
|
||||
{
|
||||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
|
||||
|
||||
JS_CHECK_RECURSION(context, return null());
|
||||
|
||||
uint32_t begin = pos().begin;
|
||||
Node literal = handler.newObjectLiteral(begin);
|
||||
if (!literal)
|
||||
return null();
|
||||
|
||||
Maybe<DeclarationKind> declKind = Some(kind);
|
||||
RootedAtom propAtom(context);
|
||||
for (;;) {
|
||||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
if (tt == TOK_RC)
|
||||
break;
|
||||
|
||||
TokenPos namePos = pos();
|
||||
|
||||
tokenStream.ungetToken();
|
||||
|
||||
PropertyType propType;
|
||||
Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom);
|
||||
if (!propName)
|
||||
return null();
|
||||
|
||||
if (propType == PropertyType::Normal) {
|
||||
// Handle e.g., |var {p: x} = o| and |var {p: x=0} = o|.
|
||||
|
||||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
|
||||
Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt);
|
||||
if (!binding)
|
||||
return null();
|
||||
|
||||
bool hasInitializer;
|
||||
if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN))
|
||||
return null();
|
||||
|
||||
Node bindingExpr = hasInitializer
|
||||
? bindingInitializer(binding, kind, yieldHandling)
|
||||
: binding;
|
||||
if (!bindingExpr)
|
||||
return null();
|
||||
|
||||
if (!handler.addPropertyDefinition(literal, propName, bindingExpr))
|
||||
return null();
|
||||
} else if (propType == PropertyType::Shorthand) {
|
||||
// Handle e.g., |var {x, y} = o| as destructuring shorthand
|
||||
// for |var {x: x, y: y} = o|.
|
||||
MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));
|
||||
|
||||
Node binding = bindingIdentifier(kind, yieldHandling);
|
||||
if (!binding)
|
||||
return null();
|
||||
|
||||
if (!handler.addShorthand(literal, propName, binding))
|
||||
return null();
|
||||
} else if (propType == PropertyType::CoverInitializedName) {
|
||||
// Handle e.g., |var {x=1, y=2} = o| as destructuring shorthand
|
||||
// with default values.
|
||||
MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));
|
||||
|
||||
Node binding = bindingIdentifier(kind, yieldHandling);
|
||||
if (!binding)
|
||||
return null();
|
||||
|
||||
tokenStream.consumeKnownToken(TOK_ASSIGN);
|
||||
|
||||
Node bindingExpr = bindingInitializer(binding, kind, yieldHandling);
|
||||
if (!bindingExpr)
|
||||
return null();
|
||||
|
||||
if (!handler.addPropertyDefinition(literal, propName, bindingExpr))
|
||||
return null();
|
||||
} else {
|
||||
errorAt(namePos.begin, JSMSG_NO_VARIABLE_NAME);
|
||||
return null();
|
||||
}
|
||||
|
||||
RootedPropertyName name(context, expr->name());
|
||||
// `yield` is already checked, so pass YieldIsName to skip that check.
|
||||
if (!checkBindingIdentifier(name, expr->pn_pos.begin, YieldIsName))
|
||||
return false;
|
||||
return noteDeclaredName(name, *maybeDecl, expr->pn_pos);
|
||||
}
|
||||
|
||||
// Otherwise this is an expression in destructuring outside a declaration.
|
||||
if (handler.isNameAnyParentheses(expr)) {
|
||||
if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(expr, context)) {
|
||||
if (!strictModeErrorAt(expr->pn_pos.begin, JSMSG_BAD_STRICT_ASSIGN, chars))
|
||||
return false;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
if (tt == TOK_RC)
|
||||
break;
|
||||
if (tt != TOK_COMMA) {
|
||||
reportMissingClosing(JSMSG_CURLY_AFTER_LIST, JSMSG_CURLY_OPENED, begin);
|
||||
return null();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (handler.isPropertyAccess(expr))
|
||||
return true;
|
||||
handler.setEndPosition(literal, pos().end);
|
||||
return literal;
|
||||
}
|
||||
|
||||
errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_TARGET);
|
||||
return false;
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling)
|
||||
{
|
||||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LB));
|
||||
|
||||
JS_CHECK_RECURSION(context, return null());
|
||||
|
||||
uint32_t begin = pos().begin;
|
||||
Node literal = handler.newArrayLiteral(begin);
|
||||
if (!literal)
|
||||
return null();
|
||||
|
||||
uint32_t index = 0;
|
||||
TokenStream::Modifier modifier = TokenStream::Operand;
|
||||
for (; ; index++) {
|
||||
if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
|
||||
error(JSMSG_ARRAY_INIT_TOO_BIG);
|
||||
return null();
|
||||
}
|
||||
|
||||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
|
||||
if (tt == TOK_RB) {
|
||||
tokenStream.ungetToken();
|
||||
break;
|
||||
}
|
||||
|
||||
if (tt == TOK_COMMA) {
|
||||
if (!handler.addElision(literal, pos()))
|
||||
return null();
|
||||
} else if (tt == TOK_TRIPLEDOT) {
|
||||
uint32_t begin = pos().begin;
|
||||
|
||||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
|
||||
Node inner = bindingIdentifierOrPattern(kind, yieldHandling, tt);
|
||||
if (!inner)
|
||||
return null();
|
||||
|
||||
if (!handler.addSpreadElement(literal, begin, inner))
|
||||
return null();
|
||||
} else {
|
||||
Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt);
|
||||
if (!binding)
|
||||
return null();
|
||||
|
||||
bool hasInitializer;
|
||||
if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN))
|
||||
return null();
|
||||
|
||||
Node element = hasInitializer
|
||||
? bindingInitializer(binding, kind, yieldHandling)
|
||||
: binding;
|
||||
if (!element)
|
||||
return null();
|
||||
|
||||
handler.addArrayElement(literal, element);
|
||||
}
|
||||
|
||||
if (tt != TOK_COMMA) {
|
||||
// If we didn't already match TOK_COMMA in above case.
|
||||
bool matched;
|
||||
if (!tokenStream.matchToken(&matched, TOK_COMMA))
|
||||
return null();
|
||||
if (!matched) {
|
||||
modifier = TokenStream::None;
|
||||
break;
|
||||
}
|
||||
if (tt == TOK_TRIPLEDOT) {
|
||||
error(JSMSG_REST_WITH_COMMA);
|
||||
return null();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RB, modifier,
|
||||
reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
|
||||
JSMSG_BRACKET_OPENED, begin));
|
||||
|
||||
handler.setEndPosition(literal, pos().end);
|
||||
return literal;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<FullParseHandler>::checkDestructuringPattern(ParseNode* pattern,
|
||||
Maybe<DeclarationKind> maybeDecl,
|
||||
PossibleError* possibleError /* = nullptr */);
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<FullParseHandler>::checkDestructuringObject(ParseNode* objectPattern,
|
||||
Maybe<DeclarationKind> maybeDecl)
|
||||
{
|
||||
MOZ_ASSERT(objectPattern->isKind(PNK_OBJECT));
|
||||
|
||||
for (ParseNode* member = objectPattern->pn_head; member; member = member->pn_next) {
|
||||
ParseNode* target;
|
||||
if (member->isKind(PNK_MUTATEPROTO)) {
|
||||
target = member->pn_kid;
|
||||
} else {
|
||||
MOZ_ASSERT(member->isKind(PNK_COLON) || member->isKind(PNK_SHORTHAND));
|
||||
MOZ_ASSERT_IF(member->isKind(PNK_SHORTHAND),
|
||||
member->pn_left->isKind(PNK_OBJECT_PROPERTY_NAME) &&
|
||||
member->pn_right->isKind(PNK_NAME) &&
|
||||
member->pn_left->pn_atom == member->pn_right->pn_atom);
|
||||
|
||||
target = member->pn_right;
|
||||
}
|
||||
if (handler.isUnparenthesizedAssignment(target))
|
||||
target = target->pn_left;
|
||||
|
||||
if (handler.isUnparenthesizedDestructuringPattern(target)) {
|
||||
if (!checkDestructuringPattern(target, maybeDecl))
|
||||
return false;
|
||||
} else {
|
||||
if (!checkDestructuringName(target, maybeDecl))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<FullParseHandler>::checkDestructuringArray(ParseNode* arrayPattern,
|
||||
Maybe<DeclarationKind> maybeDecl)
|
||||
{
|
||||
MOZ_ASSERT(arrayPattern->isKind(PNK_ARRAY));
|
||||
|
||||
for (ParseNode* element = arrayPattern->pn_head; element; element = element->pn_next) {
|
||||
if (element->isKind(PNK_ELISION))
|
||||
continue;
|
||||
|
||||
ParseNode* target;
|
||||
if (element->isKind(PNK_SPREAD)) {
|
||||
if (element->pn_next) {
|
||||
errorAt(element->pn_next->pn_pos.begin, JSMSG_PARAMETER_AFTER_REST);
|
||||
return false;
|
||||
}
|
||||
target = element->pn_kid;
|
||||
} else if (handler.isUnparenthesizedAssignment(element)) {
|
||||
target = element->pn_left;
|
||||
} else {
|
||||
target = element;
|
||||
}
|
||||
|
||||
if (handler.isUnparenthesizedDestructuringPattern(target)) {
|
||||
if (!checkDestructuringPattern(target, maybeDecl))
|
||||
return false;
|
||||
} else {
|
||||
if (!checkDestructuringName(target, maybeDecl))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destructuring patterns can appear in two kinds of contexts:
|
||||
*
|
||||
* - assignment-like: assignment expressions and |for| loop heads. In
|
||||
* these cases, the patterns' property value positions can be
|
||||
* arbitrary lvalue expressions; the destructuring is just a fancy
|
||||
* assignment.
|
||||
*
|
||||
* - binding-like: |var| and |let| declarations, functions' formal
|
||||
* parameter lists, |catch| clauses, and comprehension tails. In
|
||||
* these cases, the patterns' property value positions must be
|
||||
* simple names; the destructuring defines them as new variables.
|
||||
*
|
||||
* In both cases, other code parses the pattern as an arbitrary
|
||||
* primaryExpr, and then, here in checkDestructuringPattern, verify
|
||||
* that the tree is a valid AssignmentPattern or BindingPattern.
|
||||
*
|
||||
* In assignment-like contexts, we parse the pattern with
|
||||
* pc->inDestructuringDecl clear, so the lvalue expressions in the
|
||||
* pattern are parsed normally. primaryExpr links variable references
|
||||
* into the appropriate use chains; creates placeholder definitions;
|
||||
* and so on. checkDestructuringPattern won't bind any new names and
|
||||
* we specialize lvalues as appropriate.
|
||||
*
|
||||
* In declaration-like contexts, the normal variable reference
|
||||
* processing would just be an obstruction, because we're going to
|
||||
* define the names that appear in the property value positions as new
|
||||
* variables anyway. In this case, we parse the pattern with
|
||||
* pc->inDestructuringDecl set, which directs primaryExpr to leave
|
||||
* whatever name nodes it creates unconnected. Then, here in
|
||||
* checkDestructuringPattern, we require the pattern's property value
|
||||
* positions to be simple names, and define them as appropriate to the
|
||||
* context.
|
||||
*/
|
||||
template <>
|
||||
bool
|
||||
Parser<FullParseHandler>::checkDestructuringPattern(ParseNode* pattern,
|
||||
Maybe<DeclarationKind> maybeDecl,
|
||||
PossibleError* possibleError /* = nullptr */)
|
||||
{
|
||||
if (pattern->isKind(PNK_ARRAYCOMP)) {
|
||||
errorAt(pattern->pn_pos.begin, JSMSG_ARRAY_COMP_LEFTSIDE);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isDestructuring = pattern->isKind(PNK_ARRAY)
|
||||
? checkDestructuringArray(pattern, maybeDecl)
|
||||
: checkDestructuringObject(pattern, maybeDecl);
|
||||
|
||||
// Report any pending destructuring error.
|
||||
if (isDestructuring && possibleError && !possibleError->checkForDestructuringError())
|
||||
return false;
|
||||
|
||||
return isDestructuring;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<SyntaxParseHandler>::checkDestructuringPattern(Node pattern,
|
||||
Maybe<DeclarationKind> maybeDecl,
|
||||
PossibleError* possibleError /* = nullptr */)
|
||||
Parser<SyntaxParseHandler>::checkDestructuringAssignmentPattern(Node pattern,
|
||||
PossibleError* possibleError /* = nullptr */)
|
||||
{
|
||||
return abortIfSyntaxParser();
|
||||
}
|
||||
|
@ -4439,18 +4540,9 @@ Parser<ParseHandler>::destructuringDeclaration(DeclarationKind kind, YieldHandli
|
|||
MOZ_ASSERT(tokenStream.isCurrentTokenType(tt));
|
||||
MOZ_ASSERT(tt == TOK_LB || tt == TOK_LC);
|
||||
|
||||
PossibleError possibleError(*this);
|
||||
Node pattern;
|
||||
{
|
||||
pc->inDestructuringDecl = Some(kind);
|
||||
pattern = primaryExpr(yieldHandling, TripledotProhibited, tt, &possibleError);
|
||||
pc->inDestructuringDecl = Nothing();
|
||||
}
|
||||
|
||||
if (!pattern || !checkDestructuringPattern(pattern, Some(kind), &possibleError))
|
||||
return null();
|
||||
|
||||
return pattern;
|
||||
return tt == TOK_LB
|
||||
? arrayBindingPattern(kind, yieldHandling)
|
||||
: objectBindingPattern(kind, yieldHandling);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
|
@ -4564,6 +4656,12 @@ Parser<ParseHandler>::declarationPattern(Node decl, DeclarationKind declKind, To
|
|||
// binary operator (examined with modifier None) terminated |init|.
|
||||
// For all other declarations, through ASI's infinite majesty, a next
|
||||
// token on a new line would begin an expression.
|
||||
// Similar to the case in initializerInNameDeclaration(), we need to
|
||||
// peek at the next token when assignExpr() is a lazily parsed arrow
|
||||
// function.
|
||||
TokenKind ignored;
|
||||
if (!tokenStream.peekToken(&ignored))
|
||||
return null();
|
||||
tokenStream.addModifierException(TokenStream::OperandIsNone);
|
||||
}
|
||||
|
||||
|
@ -4946,14 +5044,6 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node impor
|
|||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool
|
||||
Parser<SyntaxParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet)
|
||||
{
|
||||
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
ParseNode*
|
||||
Parser<FullParseHandler>::importDeclaration()
|
||||
|
@ -5975,7 +6065,7 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
|
|||
|
||||
// Verify the left-hand side expression doesn't have a forbidden form.
|
||||
if (handler.isUnparenthesizedDestructuringPattern(*forInitialPart)) {
|
||||
if (!checkDestructuringPattern(*forInitialPart, Nothing(), &possibleError))
|
||||
if (!possibleError.checkForDestructuringErrorOrWarning())
|
||||
return false;
|
||||
} else if (handler.isNameAnyParentheses(*forInitialPart)) {
|
||||
const char* chars = handler.nameIsArgumentsEvalAnyParentheses(*forInitialPart, context);
|
||||
|
@ -6820,14 +6910,10 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
|
|||
return null();
|
||||
}
|
||||
|
||||
RootedPropertyName param(context, bindingIdentifier(yieldHandling));
|
||||
if (!param)
|
||||
return null();
|
||||
catchName = newName(param);
|
||||
catchName = bindingIdentifier(DeclarationKind::SimpleCatchParameter,
|
||||
yieldHandling);
|
||||
if (!catchName)
|
||||
return null();
|
||||
if (!noteDeclaredName(param, DeclarationKind::SimpleCatchParameter, pos()))
|
||||
return null();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -7055,6 +7141,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
|||
if (!classMethods)
|
||||
return null();
|
||||
|
||||
Maybe<DeclarationKind> declKind = Nothing();
|
||||
for (;;) {
|
||||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
|
@ -7089,7 +7176,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
|||
return null();
|
||||
|
||||
PropertyType propType;
|
||||
Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom);
|
||||
Node propName = propertyName(yieldHandling, declKind, classMethods, &propType, &propAtom);
|
||||
if (!propName)
|
||||
return null();
|
||||
|
||||
|
@ -7920,26 +8007,6 @@ Parser<ParseHandler>::condExpr1(InHandling inHandling, YieldHandling yieldHandli
|
|||
return handler.newConditional(condition, thenExpr, elseExpr);
|
||||
}
|
||||
|
||||
class AutoClearInDestructuringDecl
|
||||
{
|
||||
ParseContext* pc_;
|
||||
Maybe<DeclarationKind> saved_;
|
||||
|
||||
public:
|
||||
explicit AutoClearInDestructuringDecl(ParseContext* pc)
|
||||
: pc_(pc),
|
||||
saved_(pc->inDestructuringDecl)
|
||||
{
|
||||
pc->inDestructuringDecl = Nothing();
|
||||
if (saved_ && *saved_ == DeclarationKind::FormalParameter)
|
||||
pc->functionBox()->hasParameterExprs = true;
|
||||
}
|
||||
|
||||
~AutoClearInDestructuringDecl() {
|
||||
pc_->inDestructuringDecl = saved_;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandling,
|
||||
|
@ -7964,7 +8031,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
|||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
|
||||
uint32_t exprOffset = pos().begin;
|
||||
TokenPos exprPos = pos();
|
||||
|
||||
bool endsExpr;
|
||||
|
||||
|
@ -8170,12 +8237,12 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
|||
return null();
|
||||
}
|
||||
|
||||
if (!checkDestructuringPattern(lhs, Nothing(), &possibleErrorInner))
|
||||
if (!possibleErrorInner.checkForDestructuringErrorOrWarning())
|
||||
return null();
|
||||
} else if (handler.isNameAnyParentheses(lhs)) {
|
||||
if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) {
|
||||
// |chars| is "arguments" or "eval" here.
|
||||
if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars))
|
||||
if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_STRICT_ASSIGN, chars))
|
||||
return null();
|
||||
}
|
||||
|
||||
|
@ -8183,23 +8250,22 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
|||
} else if (handler.isPropertyAccess(lhs)) {
|
||||
// Permitted: no additional testing/fixup needed.
|
||||
} else if (handler.isFunctionCall(lhs)) {
|
||||
if (!strictModeErrorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS))
|
||||
if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS))
|
||||
return null();
|
||||
|
||||
if (possibleError)
|
||||
possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET);
|
||||
} else {
|
||||
errorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS);
|
||||
errorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS);
|
||||
return null();
|
||||
}
|
||||
|
||||
if (!possibleErrorInner.checkForExpressionError())
|
||||
return null();
|
||||
|
||||
Node rhs;
|
||||
{
|
||||
AutoClearInDestructuringDecl autoClear(pc);
|
||||
rhs = assignExpr(inHandling, yieldHandling, TripledotProhibited);
|
||||
if (!rhs)
|
||||
return null();
|
||||
}
|
||||
Node rhs = assignExpr(inHandling, yieldHandling, TripledotProhibited);
|
||||
if (!rhs)
|
||||
return null();
|
||||
|
||||
if (kind == PNK_ASSIGN)
|
||||
handler.checkAndSetIsDirectRHSAnonFunction(rhs);
|
||||
|
@ -9144,7 +9210,7 @@ Parser<ParseHandler>::identifierReference(Handle<PropertyName*> name)
|
|||
if (!pn)
|
||||
return null();
|
||||
|
||||
if (!pc->inDestructuringDecl && !noteUsedName(name))
|
||||
if (!noteUsedName(name))
|
||||
return null();
|
||||
|
||||
return pn;
|
||||
|
@ -9210,6 +9276,74 @@ Parser<ParseHandler>::newRegExp()
|
|||
return handler.newRegExp(reobj, pos(), *this);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
void
|
||||
Parser<ParseHandler>::checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos,
|
||||
PossibleError* possibleError)
|
||||
{
|
||||
// Return early if a pending destructuring error is already present.
|
||||
if (possibleError->hasPendingDestructuringError())
|
||||
return;
|
||||
|
||||
if (pc->sc()->needStrictChecks()) {
|
||||
if (handler.isArgumentsAnyParentheses(expr, context)) {
|
||||
if (pc->sc()->strict()) {
|
||||
possibleError->setPendingDestructuringErrorAt(exprPos,
|
||||
JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS);
|
||||
} else {
|
||||
possibleError->setPendingDestructuringWarningAt(exprPos,
|
||||
JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (handler.isEvalAnyParentheses(expr, context)) {
|
||||
if (pc->sc()->strict()) {
|
||||
possibleError->setPendingDestructuringErrorAt(exprPos,
|
||||
JSMSG_BAD_STRICT_ASSIGN_EVAL);
|
||||
} else {
|
||||
possibleError->setPendingDestructuringWarningAt(exprPos,
|
||||
JSMSG_BAD_STRICT_ASSIGN_EVAL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The expression must be either a simple assignment target, i.e. a name
|
||||
// or a property accessor, or a nested destructuring pattern.
|
||||
if (!handler.isUnparenthesizedDestructuringPattern(expr) &&
|
||||
!handler.isNameAnyParentheses(expr) &&
|
||||
!handler.isPropertyAccess(expr))
|
||||
{
|
||||
// Parentheses are forbidden around destructuring *patterns* (but
|
||||
// allowed around names). Use our nicer error message for
|
||||
// parenthesized, nested patterns.
|
||||
if (handler.isParenthesizedDestructuringPattern(expr))
|
||||
possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_PARENS);
|
||||
else
|
||||
possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
void
|
||||
Parser<ParseHandler>::checkDestructuringAssignmentElement(Node expr, TokenPos exprPos,
|
||||
PossibleError* possibleError)
|
||||
{
|
||||
// ES2018 draft rev 0719f44aab93215ed9a626b2f45bd34f36916834
|
||||
// 12.15.5 Destructuring Assignment
|
||||
//
|
||||
// AssignmentElement[Yield, Await]:
|
||||
// DestructuringAssignmentTarget[?Yield, ?Await]
|
||||
// DestructuringAssignmentTarget[?Yield, ?Await] Initializer[+In, ?Yield, ?Await]
|
||||
|
||||
// If |expr| is an assignment element with an initializer expression, its
|
||||
// destructuring assignment target was already validated in assignExpr().
|
||||
// Otherwise we need to check that |expr| is a valid destructuring target.
|
||||
if (!handler.isUnparenthesizedAssignment(expr))
|
||||
checkDestructuringAssignmentTarget(expr, exprPos, possibleError);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError)
|
||||
|
@ -9259,17 +9393,29 @@ Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleErro
|
|||
} else if (tt == TOK_TRIPLEDOT) {
|
||||
tokenStream.consumeKnownToken(TOK_TRIPLEDOT, TokenStream::Operand);
|
||||
uint32_t begin = pos().begin;
|
||||
|
||||
TokenPos innerPos;
|
||||
if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand))
|
||||
return null();
|
||||
|
||||
Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
|
||||
possibleError);
|
||||
if (!inner)
|
||||
return null();
|
||||
if (possibleError)
|
||||
checkDestructuringAssignmentTarget(inner, innerPos, possibleError);
|
||||
if (!handler.addSpreadElement(literal, begin, inner))
|
||||
return null();
|
||||
} else {
|
||||
TokenPos elementPos;
|
||||
if (!tokenStream.peekTokenPos(&elementPos, TokenStream::Operand))
|
||||
return null();
|
||||
Node element = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
|
||||
possibleError);
|
||||
if (!element)
|
||||
return null();
|
||||
if (possibleError)
|
||||
checkDestructuringAssignmentElement(element, elementPos, possibleError);
|
||||
if (foldConstants && !FoldConstants(context, &element, this))
|
||||
return null();
|
||||
handler.addArrayElement(literal, element);
|
||||
|
@ -9307,7 +9453,8 @@ DoubleToAtom(ExclusiveContext* cx, double value)
|
|||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
|
||||
Parser<ParseHandler>::propertyName(YieldHandling yieldHandling,
|
||||
const Maybe<DeclarationKind>& maybeDecl, Node propList,
|
||||
PropertyType* propType, MutableHandleAtom propAtom)
|
||||
{
|
||||
TokenKind ltok;
|
||||
|
@ -9368,7 +9515,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
|
|||
break;
|
||||
|
||||
case TOK_LB:
|
||||
propName = computedPropertyName(yieldHandling, propList);
|
||||
propName = computedPropertyName(yieldHandling, maybeDecl, propList);
|
||||
if (!propName)
|
||||
return null();
|
||||
break;
|
||||
|
@ -9426,7 +9573,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
|
|||
if (tt == TOK_LB) {
|
||||
tokenStream.consumeKnownToken(TOK_LB);
|
||||
|
||||
return computedPropertyName(yieldHandling, propList);
|
||||
return computedPropertyName(yieldHandling, maybeDecl, propList);
|
||||
}
|
||||
|
||||
// Not an accessor property after all.
|
||||
|
@ -9496,28 +9643,25 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
|
|||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::computedPropertyName(YieldHandling yieldHandling, Node literal)
|
||||
Parser<ParseHandler>::computedPropertyName(YieldHandling yieldHandling,
|
||||
const Maybe<DeclarationKind>& maybeDecl,
|
||||
Node literal)
|
||||
{
|
||||
uint32_t begin = pos().begin;
|
||||
|
||||
Node assignNode;
|
||||
{
|
||||
// Turn off the inDestructuringDecl flag when parsing computed property
|
||||
// names. In short, when parsing 'let {[x + y]: z} = obj;', noteUsedName()
|
||||
// should be called on x and y, but not on z. See the comment on
|
||||
// Parser<>::checkDestructuringPattern() for details.
|
||||
AutoClearInDestructuringDecl autoClear(pc);
|
||||
assignNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
|
||||
if (!assignNode)
|
||||
return null();
|
||||
if (maybeDecl) {
|
||||
if (*maybeDecl == DeclarationKind::FormalParameter)
|
||||
pc->functionBox()->hasParameterExprs = true;
|
||||
} else {
|
||||
handler.setListFlag(literal, PNX_NONCONST);
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_RB, JSMSG_COMP_PROP_UNTERM_EXPR);
|
||||
Node propname = handler.newComputedName(assignNode, begin, pos().end);
|
||||
if (!propname)
|
||||
Node assignNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
|
||||
if (!assignNode)
|
||||
return null();
|
||||
handler.setListFlag(literal, PNX_NONCONST);
|
||||
return propname;
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_RB, JSMSG_COMP_PROP_UNTERM_EXPR);
|
||||
return handler.newComputedName(assignNode, begin, pos().end);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
|
@ -9534,6 +9678,7 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
|||
|
||||
bool seenPrototypeMutation = false;
|
||||
bool seenCoverInitializedName = false;
|
||||
Maybe<DeclarationKind> declKind = Nothing();
|
||||
RootedAtom propAtom(context);
|
||||
for (;;) {
|
||||
TokenKind tt;
|
||||
|
@ -9547,11 +9692,14 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
|||
tokenStream.ungetToken();
|
||||
|
||||
PropertyType propType;
|
||||
Node propName = propertyName(yieldHandling, literal, &propType, &propAtom);
|
||||
Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom);
|
||||
if (!propName)
|
||||
return null();
|
||||
|
||||
if (propType == PropertyType::Normal) {
|
||||
TokenPos exprPos;
|
||||
if (!tokenStream.peekTokenPos(&exprPos, TokenStream::Operand))
|
||||
return null();
|
||||
Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
|
||||
possibleError);
|
||||
if (!propExpr)
|
||||
|
@ -9591,10 +9739,13 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
|||
if (!handler.addPropertyDefinition(literal, propName, propExpr))
|
||||
return null();
|
||||
}
|
||||
|
||||
if (possibleError)
|
||||
checkDestructuringAssignmentElement(propExpr, exprPos, possibleError);
|
||||
} else if (propType == PropertyType::Shorthand) {
|
||||
/*
|
||||
* Support, e.g., |var {x, y} = o| as destructuring shorthand
|
||||
* for |var {x: x, y: y} = o|, and |var o = {x, y}| as initializer
|
||||
* Support, e.g., |({x, y} = o)| as destructuring shorthand
|
||||
* for |({x: x, y: y} = o)|, and |var o = {x, y}| as initializer
|
||||
* shorthand for |var o = {x: x, y: y}|.
|
||||
*/
|
||||
Rooted<PropertyName*> name(context, identifierReference(yieldHandling));
|
||||
|
@ -9605,11 +9756,14 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
|||
if (!nameExpr)
|
||||
return null();
|
||||
|
||||
if (possibleError)
|
||||
checkDestructuringAssignmentTarget(nameExpr, namePos, possibleError);
|
||||
|
||||
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
|
||||
* Support, e.g., |({x=1, y=2} = o)| as destructuring shorthand
|
||||
* with default values, as per ES6 12.14.5
|
||||
*/
|
||||
Rooted<PropertyName*> name(context, identifierReference(yieldHandling));
|
||||
|
@ -9641,16 +9795,16 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
|||
possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID);
|
||||
}
|
||||
|
||||
Node rhs;
|
||||
{
|
||||
// Clearing `inDestructuringDecl` allows name use to be noted
|
||||
// in Parser::identifierReference. See bug 1255167.
|
||||
AutoClearInDestructuringDecl autoClear(pc);
|
||||
rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
|
||||
if (!rhs)
|
||||
if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) {
|
||||
// |chars| is "arguments" or "eval" here.
|
||||
if (!strictModeErrorAt(namePos.begin, JSMSG_BAD_STRICT_ASSIGN, chars))
|
||||
return null();
|
||||
}
|
||||
|
||||
Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
|
||||
if (!rhs)
|
||||
return null();
|
||||
|
||||
handler.checkAndSetIsDirectRHSAnonFunction(rhs);
|
||||
|
||||
Node propExpr = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP);
|
||||
|
@ -9659,9 +9813,6 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
|||
|
||||
if (!handler.addPropertyDefinition(literal, propName, propExpr))
|
||||
return null();
|
||||
|
||||
if (!abortIfSyntaxParser())
|
||||
return null();
|
||||
} else {
|
||||
RootedAtom funName(context);
|
||||
if (!tokenStream.isCurrentTokenType(TOK_RB)) {
|
||||
|
@ -9683,6 +9834,9 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
|||
JSOp op = JSOpFromPropertyType(propType);
|
||||
if (!handler.addObjectMethodDefinition(literal, propName, fn, op))
|
||||
return null();
|
||||
|
||||
if (possibleError)
|
||||
possibleError->setPendingDestructuringErrorAt(namePos, JSMSG_BAD_DESTRUCT_TARGET);
|
||||
}
|
||||
|
||||
if (!tokenStream.getToken(&tt))
|
||||
|
|
|
@ -340,17 +340,6 @@ class ParseContext : public Nestable<ParseContext>
|
|||
// pointer may be nullptr.
|
||||
Directives* newDirectives;
|
||||
|
||||
// Set when parsing a declaration-like destructuring pattern. This flag
|
||||
// causes PrimaryExpr to create PN_NAME parse nodes for variable references
|
||||
// which are not hooked into any definition's use chain, added to any tree
|
||||
// context's AtomList, etc. etc. checkDestructuring will do that work
|
||||
// later.
|
||||
//
|
||||
// The comments atop checkDestructuring explain the distinction between
|
||||
// assignment-like and declaration-like destructuring patterns, and why
|
||||
// they need to be treated differently.
|
||||
mozilla::Maybe<DeclarationKind> inDestructuringDecl;
|
||||
|
||||
// Set when parsing a function and it has 'return <expr>;'
|
||||
bool funHasReturnExpr;
|
||||
|
||||
|
@ -888,6 +877,12 @@ class ParserBase : public StrictModeGetter
|
|||
*/
|
||||
MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...);
|
||||
|
||||
/*
|
||||
* If extra warnings are enabled, report the given warning at the given
|
||||
* offset.
|
||||
*/
|
||||
MOZ_MUST_USE bool extraWarningAt(uint32_t offset, unsigned errorNumber, ...);
|
||||
|
||||
bool isValidStrictBinding(PropertyName* name);
|
||||
|
||||
bool warnOnceAboutExprClosure();
|
||||
|
@ -952,7 +947,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
|||
class MOZ_STACK_CLASS PossibleError
|
||||
{
|
||||
private:
|
||||
enum class ErrorKind { Expression, Destructuring };
|
||||
enum class ErrorKind { Expression, Destructuring, DestructuringWarning };
|
||||
|
||||
enum class ErrorState { None, Pending };
|
||||
|
||||
|
@ -967,11 +962,12 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
|||
Parser<ParseHandler>& parser_;
|
||||
Error exprError_;
|
||||
Error destructuringError_;
|
||||
Error destructuringWarning_;
|
||||
|
||||
// Returns the error report.
|
||||
Error& error(ErrorKind kind);
|
||||
|
||||
// Return true if an error is pending without reporting
|
||||
// Return true if an error is pending without reporting.
|
||||
bool hasError(ErrorKind kind);
|
||||
|
||||
// Resolve any pending error.
|
||||
|
@ -983,7 +979,11 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
|||
|
||||
// If there is a pending error, report it and return false, otherwise
|
||||
// return true.
|
||||
bool checkForError(ErrorKind kind);
|
||||
MOZ_MUST_USE bool checkForError(ErrorKind kind);
|
||||
|
||||
// If there is a pending warning, report it and return either false or
|
||||
// true depending on the werror option, otherwise return true.
|
||||
MOZ_MUST_USE bool checkForWarning(ErrorKind kind);
|
||||
|
||||
// Transfer an existing error to another instance.
|
||||
void transferErrorTo(ErrorKind kind, PossibleError* other);
|
||||
|
@ -991,23 +991,33 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
|||
public:
|
||||
explicit PossibleError(Parser<ParseHandler>& parser);
|
||||
|
||||
// Return true if a pending destructuring error is present.
|
||||
bool hasPendingDestructuringError();
|
||||
|
||||
// Set a pending destructuring error. Only a single error may be set
|
||||
// per instance, i.e. subsequent calls to this method are ignored and
|
||||
// won't overwrite the existing pending error.
|
||||
void setPendingDestructuringErrorAt(const TokenPos& pos, unsigned errorNumber);
|
||||
|
||||
// Set a pending destructuring warning. Only a single warning may be
|
||||
// set per instance, i.e. subsequent calls to this method are ignored
|
||||
// and won't overwrite the existing pending warning.
|
||||
void setPendingDestructuringWarningAt(const TokenPos& pos, unsigned errorNumber);
|
||||
|
||||
// Set a pending expression error. Only a single error may be set per
|
||||
// instance, i.e. subsequent calls to this method are ignored and won't
|
||||
// overwrite the existing pending error.
|
||||
void setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber);
|
||||
|
||||
// If there is a pending destructuring error, report it and return
|
||||
// false, otherwise return true. Clears any pending expression error.
|
||||
bool checkForDestructuringError();
|
||||
// If there is a pending destructuring error or warning, report it and
|
||||
// return false, otherwise return true. Clears any pending expression
|
||||
// error.
|
||||
MOZ_MUST_USE bool checkForDestructuringErrorOrWarning();
|
||||
|
||||
// If there is a pending expression error, report it and return false,
|
||||
// otherwise return true. Clears any pending destructuring error.
|
||||
bool checkForExpressionError();
|
||||
// otherwise return true. Clears any pending destructuring error or
|
||||
// warning.
|
||||
MOZ_MUST_USE bool checkForExpressionError();
|
||||
|
||||
// Pass pending errors between possible error instances. This is useful
|
||||
// for extending the lifetime of a pending error beyond the scope of
|
||||
|
@ -1490,25 +1500,27 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
|||
mozilla::Maybe<LexicalScope::Data*> newLexicalScopeData(ParseContext::Scope& scope);
|
||||
Node finishLexicalScope(ParseContext::Scope& scope, Node body);
|
||||
|
||||
Node propertyName(YieldHandling yieldHandling, Node propList,
|
||||
Node propertyName(YieldHandling yieldHandling,
|
||||
const mozilla::Maybe<DeclarationKind>& maybeDecl, Node propList,
|
||||
PropertyType* propType, MutableHandleAtom propAtom);
|
||||
Node computedPropertyName(YieldHandling yieldHandling, Node literal);
|
||||
Node computedPropertyName(YieldHandling yieldHandling,
|
||||
const mozilla::Maybe<DeclarationKind>& maybeDecl, Node literal);
|
||||
Node arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError);
|
||||
Node newRegExp();
|
||||
|
||||
Node objectLiteral(YieldHandling yieldHandling, PossibleError* possibleError);
|
||||
|
||||
// Top-level entrypoint into destructuring pattern checking/name-analyzing.
|
||||
bool checkDestructuringPattern(Node pattern, mozilla::Maybe<DeclarationKind> maybeDecl,
|
||||
PossibleError* possibleError = nullptr);
|
||||
Node bindingInitializer(Node lhs, DeclarationKind kind, YieldHandling yieldHandling);
|
||||
Node bindingIdentifier(DeclarationKind kind, YieldHandling yieldHandling);
|
||||
Node bindingIdentifierOrPattern(DeclarationKind kind, YieldHandling yieldHandling,
|
||||
TokenKind tt);
|
||||
Node objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling);
|
||||
Node arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling);
|
||||
|
||||
// Recursive methods for checking/name-analyzing subcomponents of a
|
||||
// destructuring pattern. The array/object methods *must* be passed arrays
|
||||
// or objects. The name method may be passed anything but will report an
|
||||
// error if not passed a name.
|
||||
bool checkDestructuringArray(Node arrayPattern, mozilla::Maybe<DeclarationKind> maybeDecl);
|
||||
bool checkDestructuringObject(Node objectPattern, mozilla::Maybe<DeclarationKind> maybeDecl);
|
||||
bool checkDestructuringName(Node expr, mozilla::Maybe<DeclarationKind> maybeDecl);
|
||||
void checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos,
|
||||
PossibleError* possibleError);
|
||||
void checkDestructuringAssignmentElement(Node expr, TokenPos exprPos,
|
||||
PossibleError* possibleError);
|
||||
|
||||
Node newNumber(const Token& tok) {
|
||||
return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
|
||||
|
|
|
@ -561,6 +561,10 @@ class SyntaxParseHandler
|
|||
node == NodeParenthesizedName;
|
||||
}
|
||||
|
||||
bool isArgumentsAnyParentheses(Node node, ExclusiveContext* cx) {
|
||||
return node == NodeUnparenthesizedArgumentsName || node == NodeParenthesizedArgumentsName;
|
||||
}
|
||||
|
||||
bool isEvalAnyParentheses(Node node, ExclusiveContext* cx) {
|
||||
return node == NodeUnparenthesizedEvalName || node == NodeParenthesizedEvalName;
|
||||
}
|
||||
|
@ -571,7 +575,7 @@ class SyntaxParseHandler
|
|||
|
||||
if (isEvalAnyParentheses(node, cx))
|
||||
return js_eval_str;
|
||||
if (node == NodeUnparenthesizedArgumentsName || node == NodeParenthesizedArgumentsName)
|
||||
if (isArgumentsAnyParentheses(node, cx))
|
||||
return js_arguments_str;
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -211,6 +211,8 @@ MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unar
|
|||
MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id")
|
||||
MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function")
|
||||
MSG_DEF(JSMSG_BAD_STRICT_ASSIGN, 1, JSEXN_SYNTAXERR, "'{0}' can't be defined or assigned to in strict mode code")
|
||||
MSG_DEF(JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS, 0, JSEXN_SYNTAXERR, "'arguments' can't be defined or assigned to in strict mode code")
|
||||
MSG_DEF(JSMSG_BAD_STRICT_ASSIGN_EVAL, 0, JSEXN_SYNTAXERR, "'eval' can't be defined or assigned to in strict mode code")
|
||||
MSG_DEF(JSMSG_BAD_SWITCH, 0, JSEXN_SYNTAXERR, "invalid switch statement")
|
||||
MSG_DEF(JSMSG_BAD_SUPER, 0, JSEXN_SYNTAXERR, "invalid use of keyword 'super'")
|
||||
MSG_DEF(JSMSG_BAD_SUPERPROP, 1, JSEXN_SYNTAXERR, "use of super {0} accesses only valid within methods or eval code within methods")
|
||||
|
|
Loading…
Reference in New Issue