mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-30 02:57:29 +09:00
1303703 - Part 3: Syntax parse destructuring assignment patterns.
This commit is contained in:
parent
4cd06f9368
commit
51183e0be2
5 changed files with 202 additions and 198 deletions
|
|
@ -878,6 +878,10 @@ class FullParseHandler
|
||||||
return node->isKind(PNK_NAME);
|
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) {
|
bool isEvalAnyParentheses(ParseNode* node, ExclusiveContext* cx) {
|
||||||
return node->isKind(PNK_NAME) && node->pn_atom == cx->names().eval;
|
return node->isKind(PNK_NAME) && node->pn_atom == cx->names().eval;
|
||||||
}
|
}
|
||||||
|
|
@ -888,7 +892,7 @@ class FullParseHandler
|
||||||
|
|
||||||
if (isEvalAnyParentheses(node, cx))
|
if (isEvalAnyParentheses(node, cx))
|
||||||
return js_eval_str;
|
return js_eval_str;
|
||||||
if (node->pn_atom == cx->names().arguments)
|
if (isArgumentsAnyParentheses(node, cx))
|
||||||
return js_arguments_str;
|
return js_arguments_str;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -689,6 +689,19 @@ ParserBase::extraWarning(unsigned errorNumber, ...)
|
||||||
return result;
|
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
|
bool
|
||||||
ParserBase::strictModeError(unsigned errorNumber, ...)
|
ParserBase::strictModeError(unsigned errorNumber, ...)
|
||||||
{
|
{
|
||||||
|
|
@ -743,14 +756,6 @@ ParserBase::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumb
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
|
||||||
bool
|
|
||||||
Parser<FullParseHandler>::abortIfSyntaxParser()
|
|
||||||
{
|
|
||||||
handler.disableSyntaxParser();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
bool
|
bool
|
||||||
Parser<SyntaxParseHandler>::abortIfSyntaxParser()
|
Parser<SyntaxParseHandler>::abortIfSyntaxParser()
|
||||||
|
|
@ -4128,8 +4133,17 @@ Parser<ParseHandler>::PossibleError::error(ErrorKind kind)
|
||||||
{
|
{
|
||||||
if (kind == ErrorKind::Expression)
|
if (kind == ErrorKind::Expression)
|
||||||
return exprError_;
|
return exprError_;
|
||||||
MOZ_ASSERT(kind == ErrorKind::Destructuring);
|
if (kind == ErrorKind::Destructuring)
|
||||||
return destructuringError_;
|
return destructuringError_;
|
||||||
|
MOZ_ASSERT(kind == ErrorKind::DestructuringWarning);
|
||||||
|
return destructuringWarning_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ParseHandler>
|
||||||
|
bool
|
||||||
|
Parser<ParseHandler>::PossibleError::hasPendingDestructuringError()
|
||||||
|
{
|
||||||
|
return hasError(ErrorKind::Destructuring);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
|
|
@ -4171,6 +4185,14 @@ Parser<ParseHandler>::PossibleError::setPendingDestructuringErrorAt(const TokenP
|
||||||
setPending(ErrorKind::Destructuring, pos, errorNumber);
|
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>
|
template <typename ParseHandler>
|
||||||
void
|
void
|
||||||
Parser<ParseHandler>::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos,
|
Parser<ParseHandler>::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos,
|
||||||
|
|
@ -4193,23 +4215,36 @@ Parser<ParseHandler>::PossibleError::checkForError(ErrorKind kind)
|
||||||
|
|
||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
bool
|
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
|
// Clear pending expression error, because we're definitely not in an
|
||||||
// expression context.
|
// expression context.
|
||||||
setResolved(ErrorKind::Expression);
|
setResolved(ErrorKind::Expression);
|
||||||
|
|
||||||
// Report any pending destructuring error.
|
// Report any pending destructuring error or warning.
|
||||||
return checkForError(ErrorKind::Destructuring);
|
return checkForError(ErrorKind::Destructuring) &&
|
||||||
|
checkForWarning(ErrorKind::DestructuringWarning);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
bool
|
bool
|
||||||
Parser<ParseHandler>::PossibleError::checkForExpressionError()
|
Parser<ParseHandler>::PossibleError::checkForExpressionError()
|
||||||
{
|
{
|
||||||
// Clear pending destructuring error, because we're definitely not in a
|
// Clear pending destructuring error or warning, because we're definitely
|
||||||
// destructuring context.
|
// not in a destructuring context.
|
||||||
setResolved(ErrorKind::Destructuring);
|
setResolved(ErrorKind::Destructuring);
|
||||||
|
setResolved(ErrorKind::DestructuringWarning);
|
||||||
|
|
||||||
// Report any pending expression error.
|
// Report any pending expression error.
|
||||||
return checkForError(ErrorKind::Expression);
|
return checkForError(ErrorKind::Expression);
|
||||||
|
|
@ -4241,150 +4276,6 @@ Parser<ParseHandler>::PossibleError::transferErrorsTo(PossibleError* other)
|
||||||
transferErrorTo(ErrorKind::Expression, other);
|
transferErrorTo(ErrorKind::Expression, other);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
|
||||||
bool
|
|
||||||
Parser<FullParseHandler>::checkDestructuringAssignmentName(ParseNode* expr)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!handler.isUnparenthesizedDestructuringPattern(expr));
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The expression must be a simple assignment target, i.e. either a name
|
|
||||||
// or a property accessor.
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handler.isPropertyAccess(expr))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_TARGET);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
bool
|
|
||||||
Parser<FullParseHandler>::checkDestructuringAssignmentPattern(ParseNode* pattern,
|
|
||||||
PossibleError* possibleError /* = nullptr */);
|
|
||||||
|
|
||||||
template <>
|
|
||||||
bool
|
|
||||||
Parser<FullParseHandler>::checkDestructuringAssignmentObject(ParseNode* objectPattern)
|
|
||||||
{
|
|
||||||
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 (!checkDestructuringAssignmentPattern(target))
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
if (!checkDestructuringAssignmentName(target))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
bool
|
|
||||||
Parser<FullParseHandler>::checkDestructuringAssignmentArray(ParseNode* arrayPattern)
|
|
||||||
{
|
|
||||||
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 (!checkDestructuringAssignmentPattern(target))
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
if (!checkDestructuringAssignmentName(target))
|
|
||||||
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 the first case, other code parses the pattern as an arbitrary
|
|
||||||
* primaryExpr, and then, here in checkDestructuringAssignmentPattern, verify
|
|
||||||
* that the tree is a valid AssignmentPattern.
|
|
||||||
*/
|
|
||||||
template <>
|
|
||||||
bool
|
|
||||||
Parser<FullParseHandler>::checkDestructuringAssignmentPattern(ParseNode* pattern,
|
|
||||||
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)
|
|
||||||
? checkDestructuringAssignmentArray(pattern)
|
|
||||||
: checkDestructuringAssignmentObject(pattern);
|
|
||||||
|
|
||||||
// Report any pending destructuring error.
|
|
||||||
if (isDestructuring && possibleError && !possibleError->checkForDestructuringError())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return isDestructuring;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::bindingInitializer(Node lhs, DeclarationKind kind,
|
Parser<ParseHandler>::bindingInitializer(Node lhs, DeclarationKind kind,
|
||||||
|
|
@ -5153,14 +5044,6 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node impor
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
|
||||||
bool
|
|
||||||
Parser<SyntaxParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet)
|
|
||||||
{
|
|
||||||
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
ParseNode*
|
ParseNode*
|
||||||
Parser<FullParseHandler>::importDeclaration()
|
Parser<FullParseHandler>::importDeclaration()
|
||||||
|
|
@ -6182,7 +6065,7 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
|
||||||
|
|
||||||
// Verify the left-hand side expression doesn't have a forbidden form.
|
// Verify the left-hand side expression doesn't have a forbidden form.
|
||||||
if (handler.isUnparenthesizedDestructuringPattern(*forInitialPart)) {
|
if (handler.isUnparenthesizedDestructuringPattern(*forInitialPart)) {
|
||||||
if (!checkDestructuringAssignmentPattern(*forInitialPart, &possibleError))
|
if (!possibleError.checkForDestructuringErrorOrWarning())
|
||||||
return false;
|
return false;
|
||||||
} else if (handler.isNameAnyParentheses(*forInitialPart)) {
|
} else if (handler.isNameAnyParentheses(*forInitialPart)) {
|
||||||
const char* chars = handler.nameIsArgumentsEvalAnyParentheses(*forInitialPart, context);
|
const char* chars = handler.nameIsArgumentsEvalAnyParentheses(*forInitialPart, context);
|
||||||
|
|
@ -8148,7 +8031,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
||||||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
uint32_t exprOffset = pos().begin;
|
TokenPos exprPos = pos();
|
||||||
|
|
||||||
bool endsExpr;
|
bool endsExpr;
|
||||||
|
|
||||||
|
|
@ -8354,12 +8237,12 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checkDestructuringAssignmentPattern(lhs, &possibleErrorInner))
|
if (!possibleErrorInner.checkForDestructuringErrorOrWarning())
|
||||||
return null();
|
return null();
|
||||||
} else if (handler.isNameAnyParentheses(lhs)) {
|
} else if (handler.isNameAnyParentheses(lhs)) {
|
||||||
if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) {
|
if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) {
|
||||||
// |chars| is "arguments" or "eval" here.
|
// |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();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8367,10 +8250,13 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
||||||
} else if (handler.isPropertyAccess(lhs)) {
|
} else if (handler.isPropertyAccess(lhs)) {
|
||||||
// Permitted: no additional testing/fixup needed.
|
// Permitted: no additional testing/fixup needed.
|
||||||
} else if (handler.isFunctionCall(lhs)) {
|
} else if (handler.isFunctionCall(lhs)) {
|
||||||
if (!strictModeErrorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS))
|
if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
|
if (possibleError)
|
||||||
|
possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET);
|
||||||
} else {
|
} else {
|
||||||
errorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS);
|
errorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS);
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -9390,6 +9276,74 @@ Parser<ParseHandler>::newRegExp()
|
||||||
return handler.newRegExp(reobj, pos(), *this);
|
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>
|
template <typename ParseHandler>
|
||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError)
|
Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError)
|
||||||
|
|
@ -9439,17 +9393,29 @@ Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleErro
|
||||||
} else if (tt == TOK_TRIPLEDOT) {
|
} else if (tt == TOK_TRIPLEDOT) {
|
||||||
tokenStream.consumeKnownToken(TOK_TRIPLEDOT, TokenStream::Operand);
|
tokenStream.consumeKnownToken(TOK_TRIPLEDOT, TokenStream::Operand);
|
||||||
uint32_t begin = pos().begin;
|
uint32_t begin = pos().begin;
|
||||||
|
|
||||||
|
TokenPos innerPos;
|
||||||
|
if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand))
|
||||||
|
return null();
|
||||||
|
|
||||||
Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
|
Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
|
||||||
possibleError);
|
possibleError);
|
||||||
if (!inner)
|
if (!inner)
|
||||||
return null();
|
return null();
|
||||||
|
if (possibleError)
|
||||||
|
checkDestructuringAssignmentTarget(inner, innerPos, possibleError);
|
||||||
if (!handler.addSpreadElement(literal, begin, inner))
|
if (!handler.addSpreadElement(literal, begin, inner))
|
||||||
return null();
|
return null();
|
||||||
} else {
|
} else {
|
||||||
|
TokenPos elementPos;
|
||||||
|
if (!tokenStream.peekTokenPos(&elementPos, TokenStream::Operand))
|
||||||
|
return null();
|
||||||
Node element = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
|
Node element = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
|
||||||
possibleError);
|
possibleError);
|
||||||
if (!element)
|
if (!element)
|
||||||
return null();
|
return null();
|
||||||
|
if (possibleError)
|
||||||
|
checkDestructuringAssignmentElement(element, elementPos, possibleError);
|
||||||
if (foldConstants && !FoldConstants(context, &element, this))
|
if (foldConstants && !FoldConstants(context, &element, this))
|
||||||
return null();
|
return null();
|
||||||
handler.addArrayElement(literal, element);
|
handler.addArrayElement(literal, element);
|
||||||
|
|
@ -9731,6 +9697,9 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
if (propType == PropertyType::Normal) {
|
if (propType == PropertyType::Normal) {
|
||||||
|
TokenPos exprPos;
|
||||||
|
if (!tokenStream.peekTokenPos(&exprPos, TokenStream::Operand))
|
||||||
|
return null();
|
||||||
Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
|
Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
|
||||||
possibleError);
|
possibleError);
|
||||||
if (!propExpr)
|
if (!propExpr)
|
||||||
|
|
@ -9770,6 +9739,9 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
||||||
if (!handler.addPropertyDefinition(literal, propName, propExpr))
|
if (!handler.addPropertyDefinition(literal, propName, propExpr))
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (possibleError)
|
||||||
|
checkDestructuringAssignmentElement(propExpr, exprPos, possibleError);
|
||||||
} else if (propType == PropertyType::Shorthand) {
|
} else if (propType == PropertyType::Shorthand) {
|
||||||
/*
|
/*
|
||||||
* Support, e.g., |({x, y} = o)| as destructuring shorthand
|
* Support, e.g., |({x, y} = o)| as destructuring shorthand
|
||||||
|
|
@ -9784,6 +9756,9 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
||||||
if (!nameExpr)
|
if (!nameExpr)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
|
if (possibleError)
|
||||||
|
checkDestructuringAssignmentTarget(nameExpr, namePos, possibleError);
|
||||||
|
|
||||||
if (!handler.addShorthand(literal, propName, nameExpr))
|
if (!handler.addShorthand(literal, propName, nameExpr))
|
||||||
return null();
|
return null();
|
||||||
} else if (propType == PropertyType::CoverInitializedName) {
|
} else if (propType == PropertyType::CoverInitializedName) {
|
||||||
|
|
@ -9820,6 +9795,12 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
||||||
possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID);
|
possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
|
||||||
if (!rhs)
|
if (!rhs)
|
||||||
return null();
|
return null();
|
||||||
|
|
@ -9832,9 +9813,6 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
||||||
|
|
||||||
if (!handler.addPropertyDefinition(literal, propName, propExpr))
|
if (!handler.addPropertyDefinition(literal, propName, propExpr))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
if (!abortIfSyntaxParser())
|
|
||||||
return null();
|
|
||||||
} else {
|
} else {
|
||||||
RootedAtom funName(context);
|
RootedAtom funName(context);
|
||||||
if (!tokenStream.isCurrentTokenType(TOK_RB)) {
|
if (!tokenStream.isCurrentTokenType(TOK_RB)) {
|
||||||
|
|
@ -9856,6 +9834,9 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
||||||
JSOp op = JSOpFromPropertyType(propType);
|
JSOp op = JSOpFromPropertyType(propType);
|
||||||
if (!handler.addObjectMethodDefinition(literal, propName, fn, op))
|
if (!handler.addObjectMethodDefinition(literal, propName, fn, op))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
|
if (possibleError)
|
||||||
|
possibleError->setPendingDestructuringErrorAt(namePos, JSMSG_BAD_DESTRUCT_TARGET);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tokenStream.getToken(&tt))
|
if (!tokenStream.getToken(&tt))
|
||||||
|
|
|
||||||
|
|
@ -877,6 +877,12 @@ class ParserBase : public StrictModeGetter
|
||||||
*/
|
*/
|
||||||
MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...);
|
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 isValidStrictBinding(PropertyName* name);
|
||||||
|
|
||||||
bool warnOnceAboutExprClosure();
|
bool warnOnceAboutExprClosure();
|
||||||
|
|
@ -941,7 +947,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||||
class MOZ_STACK_CLASS PossibleError
|
class MOZ_STACK_CLASS PossibleError
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
enum class ErrorKind { Expression, Destructuring };
|
enum class ErrorKind { Expression, Destructuring, DestructuringWarning };
|
||||||
|
|
||||||
enum class ErrorState { None, Pending };
|
enum class ErrorState { None, Pending };
|
||||||
|
|
||||||
|
|
@ -956,11 +962,12 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||||
Parser<ParseHandler>& parser_;
|
Parser<ParseHandler>& parser_;
|
||||||
Error exprError_;
|
Error exprError_;
|
||||||
Error destructuringError_;
|
Error destructuringError_;
|
||||||
|
Error destructuringWarning_;
|
||||||
|
|
||||||
// Returns the error report.
|
// Returns the error report.
|
||||||
Error& error(ErrorKind kind);
|
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);
|
bool hasError(ErrorKind kind);
|
||||||
|
|
||||||
// Resolve any pending error.
|
// Resolve any pending error.
|
||||||
|
|
@ -972,7 +979,11 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||||
|
|
||||||
// If there is a pending error, report it and return false, otherwise
|
// If there is a pending error, report it and return false, otherwise
|
||||||
// return true.
|
// 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.
|
// Transfer an existing error to another instance.
|
||||||
void transferErrorTo(ErrorKind kind, PossibleError* other);
|
void transferErrorTo(ErrorKind kind, PossibleError* other);
|
||||||
|
|
@ -980,23 +991,33 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||||
public:
|
public:
|
||||||
explicit PossibleError(Parser<ParseHandler>& parser);
|
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
|
// Set a pending destructuring error. Only a single error may be set
|
||||||
// per instance, i.e. subsequent calls to this method are ignored and
|
// per instance, i.e. subsequent calls to this method are ignored and
|
||||||
// won't overwrite the existing pending error.
|
// won't overwrite the existing pending error.
|
||||||
void setPendingDestructuringErrorAt(const TokenPos& pos, unsigned errorNumber);
|
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
|
// 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
|
// instance, i.e. subsequent calls to this method are ignored and won't
|
||||||
// overwrite the existing pending error.
|
// overwrite the existing pending error.
|
||||||
void setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber);
|
void setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber);
|
||||||
|
|
||||||
// If there is a pending destructuring error, report it and return
|
// If there is a pending destructuring error or warning, report it and
|
||||||
// false, otherwise return true. Clears any pending expression error.
|
// return false, otherwise return true. Clears any pending expression
|
||||||
bool checkForDestructuringError();
|
// error.
|
||||||
|
MOZ_MUST_USE bool checkForDestructuringErrorOrWarning();
|
||||||
|
|
||||||
// If there is a pending expression error, report it and return false,
|
// If there is a pending expression error, report it and return false,
|
||||||
// otherwise return true. Clears any pending destructuring error.
|
// otherwise return true. Clears any pending destructuring error or
|
||||||
bool checkForExpressionError();
|
// warning.
|
||||||
|
MOZ_MUST_USE bool checkForExpressionError();
|
||||||
|
|
||||||
// Pass pending errors between possible error instances. This is useful
|
// Pass pending errors between possible error instances. This is useful
|
||||||
// for extending the lifetime of a pending error beyond the scope of
|
// for extending the lifetime of a pending error beyond the scope of
|
||||||
|
|
@ -1496,18 +1517,10 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||||
Node objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling);
|
Node objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling);
|
||||||
Node arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling);
|
Node arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling);
|
||||||
|
|
||||||
// Top-level entrypoint into destructuring assignment pattern checking and
|
void checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos,
|
||||||
// name-analyzing.
|
PossibleError* possibleError);
|
||||||
bool checkDestructuringAssignmentPattern(Node pattern,
|
void checkDestructuringAssignmentElement(Node expr, TokenPos exprPos,
|
||||||
PossibleError* possibleError = nullptr);
|
PossibleError* possibleError);
|
||||||
|
|
||||||
// Recursive methods for checking/name-analyzing subcomponents of an
|
|
||||||
// destructuring assignment 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 checkDestructuringAssignmentArray(Node arrayPattern);
|
|
||||||
bool checkDestructuringAssignmentObject(Node objectPattern);
|
|
||||||
bool checkDestructuringAssignmentName(Node expr);
|
|
||||||
|
|
||||||
Node newNumber(const Token& tok) {
|
Node newNumber(const Token& tok) {
|
||||||
return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
|
return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
|
||||||
|
|
|
||||||
|
|
@ -561,6 +561,10 @@ class SyntaxParseHandler
|
||||||
node == NodeParenthesizedName;
|
node == NodeParenthesizedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isArgumentsAnyParentheses(Node node, ExclusiveContext* cx) {
|
||||||
|
return node == NodeUnparenthesizedArgumentsName || node == NodeParenthesizedArgumentsName;
|
||||||
|
}
|
||||||
|
|
||||||
bool isEvalAnyParentheses(Node node, ExclusiveContext* cx) {
|
bool isEvalAnyParentheses(Node node, ExclusiveContext* cx) {
|
||||||
return node == NodeUnparenthesizedEvalName || node == NodeParenthesizedEvalName;
|
return node == NodeUnparenthesizedEvalName || node == NodeParenthesizedEvalName;
|
||||||
}
|
}
|
||||||
|
|
@ -571,7 +575,7 @@ class SyntaxParseHandler
|
||||||
|
|
||||||
if (isEvalAnyParentheses(node, cx))
|
if (isEvalAnyParentheses(node, cx))
|
||||||
return js_eval_str;
|
return js_eval_str;
|
||||||
if (node == NodeUnparenthesizedArgumentsName || node == NodeParenthesizedArgumentsName)
|
if (isArgumentsAnyParentheses(node, cx))
|
||||||
return js_arguments_str;
|
return js_arguments_str;
|
||||||
return nullptr;
|
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_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_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, 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_SWITCH, 0, JSEXN_SYNTAXERR, "invalid switch statement")
|
||||||
MSG_DEF(JSMSG_BAD_SUPER, 0, JSEXN_SYNTAXERR, "invalid use of keyword 'super'")
|
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")
|
MSG_DEF(JSMSG_BAD_SUPERPROP, 1, JSEXN_SYNTAXERR, "use of super {0} accesses only valid within methods or eval code within methods")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue