Ignore:
Timestamp:
Nov 19, 2015, 2:54:46 PM (10 years ago)
Author:
[email protected]
Message:

[JSC] Fix AssignmentElement parsing
https://bugs.webkit.org/show_bug.cgi?id=151026

Patch by Caitlin Potter <[email protected]> on 2015-11-19
Reviewed by Geoffrey Garen.

When parsing an AssignmentPattern, any LeftHandSideExpression which
is a valid assignment target is acceptable.

Additionally, this change minimizes the amount of time spent
re-parsing ObjectLiteral and ArrayLiterals, by parsing as an
Expression first (the common case), and re-parsing only if the
result is a valid ObjectLiteral or ArrayLiteral followed by an =,
or if an error specifically indicates that the expression could
have been parsed as an AssignmentPattern.

  • bytecompiler/NodesCodegen.cpp:

(JSC::AssignmentElementNode::collectBoundIdentifiers):
(JSC::AssignmentElementNode::bindValue):
(JSC::AssignmentElementNode::toString):

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::isAssignmentLocation):
(JSC::ASTBuilder::isObjectLiteral):
(JSC::ASTBuilder::isArrayLiteral):
(JSC::ASTBuilder::isObjectOrArrayLiteral):
(JSC::ASTBuilder::createAssignmentElement):

  • parser/NodeConstructors.h:

(JSC::AssignmentElementNode::AssignmentElementNode):

  • parser/Nodes.h:

(JSC::ExpressionNode::isObjectLiteral):
(JSC::ExpressionNode::isArrayLiteral):
(JSC::AssignmentElementNode::assignmentTarget):
(JSC::AssignmentElementNode::divotStart):
(JSC::AssignmentElementNode::divotEnd):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::Parser):
(JSC::Parser<LexerType>::createAssignmentElement):
(JSC::Parser<LexerType>::parseBindingOrAssignmentElement):
(JSC::Parser<LexerType>::parseAssignmentElement):
(JSC::Parser<LexerType>::parseDestructuringPattern):
(JSC::Parser<LexerType>::parseAssignmentExpression):
(JSC::Parser<LexerType>::parseProperty):

  • parser/Parser.h:

(JSC::Parser::ExpressionErrorClassifier::ExpressionErrorClassifier):
(JSC::Parser::ExpressionErrorClassifier::~ExpressionErrorClassifier):
(JSC::Parser::ExpressionErrorClassifier::classifyExpressionError):
(JSC::Parser::ExpressionErrorClassifier::indicatesPossiblePattern):
(JSC::Parser::classifyExpressionError):

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::operatorStackPop):

  • tests/es6.yaml:
  • tests/es6/destructuring_assignment_non_simple_target.js: Added.

(test.):
(test):

  • tests/es6/destructuring_initializer_scoping.js: Added.

(test.tester):

  • tests/stress/destructuring-assignment-syntax.js: Added.

(testSyntax):
(testSyntaxError):

  • tests/stress/rest-elements.js:

(shouldThrow): Deleted.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r192603 r192661  
    6161#define semanticFailIfFalse(cond, ...) do { if (!(cond)) internalFailWithMessage(false, __VA_ARGS__); } while (0)
    6262#define regexFail(failure) do { setErrorMessage(failure); return 0; } while (0)
     63#define restoreSavePointAndFail(savePoint, message) do { restoreSavePointWithError(savePoint, message); return 0; } while (0)
    6364#define failDueToUnexpectedToken() do {\
    6465        logError(true);\
     
    220221    m_token.m_location.lineStartOffset = source.startOffset();
    221222    m_functionCache = vm->addSourceProviderCache(source.provider());
     223    m_expressionErrorClassifier = nullptr;
    222224
    223225    ScopeRef scope = pushScope();
     
    713715
    714716template <typename LexerType>
     717template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern Parser<LexerType>::createAssignmentElement(TreeBuilder& context, TreeExpression& assignmentTarget, const JSTextPosition& startPosition, const JSTextPosition& endPosition)
     718{
     719    return context.createAssignmentElement(assignmentTarget, startPosition, endPosition);
     720}
     721
     722template <typename LexerType>
    715723template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseArrowFunctionSingleExpressionBodySourceElements(TreeBuilder& context)
    716724{
     
    745753{
    746754    return parseDestructuringPattern(context, DestructureToExpressions, ExportType::NotExported, nullptr, nullptr, bindingContext);
     755}
     756
     757template <typename LexerType>
     758template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseBindingOrAssignmentElement(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
     759{
     760    if (kind == DestructureToExpressions)
     761        return parseAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
     762    return parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
     763}
     764
     765template <typename LexerType>
     766template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseAssignmentElement(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
     767{
     768    SavePoint savePoint = createSavePoint();
     769    TreeDestructuringPattern assignmentTarget = 0;
     770
     771    if (match(OPENBRACE) || match(OPENBRACKET))
     772        assignmentTarget = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
     773    if (!assignmentTarget || match(DOT) || match(OPENBRACKET) || match(OPENPAREN) || match(TEMPLATE)) {
     774        restoreSavePoint(savePoint);
     775        JSTextPosition startPosition = tokenStartPosition();
     776        auto element = parseMemberExpression(context);
     777
     778        semanticFailIfFalse(element && context.isAssignmentLocation(element), "Invalid destructuring assignment target");
     779
     780        return createAssignmentElement(context, element, startPosition, lastTokenEndPosition());
     781    }
     782    return assignmentTarget;
    747783}
    748784
     
    777813                JSTokenLocation location = m_token.m_location;
    778814                next();
    779                 auto innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
     815                auto innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    780816                if (kind == DestructureToExpressions && !innerPattern)
    781817                    return 0;
     
    790826
    791827            JSTokenLocation location = m_token.m_location;
    792             auto innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
     828            auto innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    793829            if (kind == DestructureToExpressions && !innerPattern)
    794830                return 0;
     
    798834        } while (consume(COMMA));
    799835
    800         if (kind == DestructureToExpressions && !match(CLOSEBRACKET))
    801             return 0;
    802836        consumeOrFail(CLOSEBRACKET, restElementWasFound ? "Expected a closing ']' following a rest element destructuring pattern" : "Expected either a closing ']' or a ',' following an element destructuring pattern");
    803837        context.finishArrayPattern(arrayPattern, divotStart, divotStart, lastTokenEndPosition());
     
    827861                next();
    828862                if (consume(COLON))
    829                     innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
     863                    innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    830864                else
    831865                    innerPattern = createBindingPattern(context, kind, exportType, *propertyName, identifierToken, bindingContext, duplicateIdentifier);
     
    860894                    failWithMessage("Expected a ':' prior to a named destructuring property");
    861895                }
    862                 innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
     896                innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    863897            }
    864898            if (kind == DestructureToExpressions && !innerPattern)
     
    26712705    int initialAssignmentCount = m_assignmentCount;
    26722706    int initialNonLHSCount = m_nonLHSCount;
    2673     if (match(OPENBRACE) || match(OPENBRACKET)) {
    2674         SavePoint savePoint = createSavePoint();
    2675         auto pattern = tryParseDestructuringPatternExpression(context, AssignmentContext::AssignmentExpression);
    2676         if (pattern && consume(EQUAL)) {
    2677             auto rhs = parseAssignmentExpression(context);
    2678             if (rhs)
    2679                 return context.createDestructuringAssignment(location, pattern, rhs);
    2680         }
    2681         restoreSavePoint(savePoint);
    2682     }
     2707    bool maybeAssignmentPattern = match(OPENBRACE) || match(OPENBRACKET);
     2708    SavePoint savePoint = createSavePoint();
     2709    ExpressionErrorClassifier classifier(this);
    26832710
    26842711#if ENABLE(ES6_GENERATORS)
     
    26932720   
    26942721    TreeExpression lhs = parseConditionalExpression(context);
     2722
     2723    if (!lhs && (!maybeAssignmentPattern || !classifier.indicatesPossiblePattern()))
     2724        propagateError();
     2725
     2726    if (maybeAssignmentPattern && (!lhs || (context.isObjectOrArrayLiteral(lhs) && match(EQUAL)))) {
     2727        String expressionError = m_errorMessage;
     2728        SavePoint expressionErrorLocation = createSavePointForError();
     2729        restoreSavePoint(savePoint);
     2730        auto pattern = tryParseDestructuringPatternExpression(context, AssignmentContext::AssignmentExpression);
     2731        if (classifier.indicatesPossiblePattern() && (!pattern || !match(EQUAL)))
     2732            restoreSavePointAndFail(expressionErrorLocation, expressionError);
     2733        failIfFalse(pattern, "Cannot parse assignment pattern");
     2734        consumeOrFail(EQUAL, "Expected '=' following assignment pattern");
     2735        auto rhs = parseAssignmentExpression(context);
     2736        if (!rhs)
     2737            propagateError();
     2738        return context.createDestructuringAssignment(location, pattern, rhs);
     2739    }
     2740
    26952741    failIfFalse(lhs, "Cannot parse expression");
    26962742    if (initialNonLHSCount != m_nonLHSCount) {
     
    29112957            return context.createProperty(ident, node, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Shorthand), PropertyNode::KnownDirect, complete);
    29122958        }
     2959
     2960        if (match(EQUAL)) // CoverInitializedName is exclusive to BindingPattern and AssignmentPattern
     2961            classifyExpressionError(ErrorIndicatesPattern);
    29132962
    29142963        PropertyNode::Type type;
Note: See TracChangeset for help on using the changeset viewer.