Changeset 192436 in webkit


Ignore:
Timestamp:
Nov 13, 2015, 11:13:39 AM (10 years ago)
Author:
[email protected]
Message:

Allow any LeftHandSideExpression as a valid AssignmentElement
https://bugs.webkit.org/show_bug.cgi?id=151026

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

  • bytecompiler/NodesCodegen.cpp:

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

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::isAssignmentLocation):
(JSC::ASTBuilder::createAssignmentElement):

  • parser/NodeConstructors.h:

(JSC::AssignmentElementNode::AssignmentElementNode):

  • parser/Nodes.h:

(JSC::AssignmentElementNode::assignmentTarget):
(JSC::AssignmentElementNode::divotStart):
(JSC::AssignmentElementNode::divotEnd):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::createAssignmentElement):
(JSC::Parser<LexerType>::parseDestructuringPattern):

  • parser/Parser.h:
  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::operatorStackPop):

Location:
trunk/Source/JavaScriptCore
Files:
3 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r192434 r192436  
     12015-11-13  Caitlin Potter  <[email protected]>
     2
     3        Allow any LeftHandSideExpression as a valid AssignmentElement
     4        https://bugs.webkit.org/show_bug.cgi?id=151026
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        * bytecompiler/NodesCodegen.cpp:
     9        (JSC::AssignmentElementNode::collectBoundIdentifiers):
     10        (JSC::AssignmentElementNode::bindValue):
     11        (JSC::AssignmentElementNode::toString):
     12        * parser/ASTBuilder.h:
     13        (JSC::ASTBuilder::isAssignmentLocation):
     14        (JSC::ASTBuilder::createAssignmentElement):
     15        * parser/NodeConstructors.h:
     16        (JSC::AssignmentElementNode::AssignmentElementNode):
     17        * parser/Nodes.h:
     18        (JSC::AssignmentElementNode::assignmentTarget):
     19        (JSC::AssignmentElementNode::divotStart):
     20        (JSC::AssignmentElementNode::divotEnd):
     21        * parser/Parser.cpp:
     22        (JSC::Parser<LexerType>::createAssignmentElement):
     23        (JSC::Parser<LexerType>::parseDestructuringPattern):
     24        * parser/Parser.h:
     25        * parser/SyntaxChecker.h:
     26        (JSC::SyntaxChecker::operatorStackPop):
     27
    1282015-11-13  Yusuke Suzuki  <[email protected]>
    229
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r192155 r192436  
    33983398    identifiers.append(m_boundProperty);
    33993399}
    3400    
     3400
     3401void AssignmentElementNode::collectBoundIdentifiers(Vector<Identifier>&) const
     3402{
     3403}
     3404
     3405void AssignmentElementNode::bindValue(BytecodeGenerator& generator, RegisterID* value) const
     3406{
     3407    if (m_assignmentTarget->isResolveNode()) {
     3408        ResolveNode* lhs = static_cast<ResolveNode*>(m_assignmentTarget);
     3409        Variable var = generator.variable(lhs->identifier());
     3410        bool isReadOnly = var.isReadOnly();
     3411        if (RegisterID* local = var.local()) {
     3412            generator.emitTDZCheckIfNecessary(var, local, nullptr);
     3413
     3414            if (isReadOnly)
     3415                generator.emitReadOnlyExceptionIfNeeded(var);
     3416            else {
     3417                generator.invalidateForInContextForLocal(local);
     3418                generator.moveToDestinationIfNeeded(local, value);
     3419                generator.emitProfileType(local, divotStart(), divotEnd());
     3420            }
     3421            return;
     3422        }
     3423        if (generator.isStrictMode())
     3424            generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
     3425        RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
     3426        generator.emitTDZCheckIfNecessary(var, nullptr, scope.get());
     3427        if (isReadOnly) {
     3428            bool threwException = generator.emitReadOnlyExceptionIfNeeded(var);
     3429            if (threwException)
     3430                return;
     3431        }
     3432        generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
     3433        if (!isReadOnly) {
     3434            generator.emitPutToScope(scope.get(), var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, NotInitialization);
     3435            generator.emitProfileType(value, var, divotStart(), divotEnd());
     3436        }
     3437    } else if (m_assignmentTarget->isDotAccessorNode()) {
     3438        DotAccessorNode* lhs = static_cast<DotAccessorNode*>(m_assignmentTarget);
     3439        RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(lhs->base(), true, false);
     3440        generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
     3441        generator.emitPutById(base.get(), lhs->identifier(), value);
     3442        generator.emitProfileType(value, divotStart(), divotEnd());
     3443    } else if (m_assignmentTarget->isBracketAccessorNode()) {
     3444        BracketAccessorNode* lhs = static_cast<BracketAccessorNode*>(m_assignmentTarget);
     3445        RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(lhs->base(), true, false);
     3446        RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(lhs->subscript(), true, false);
     3447        generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
     3448        generator.emitPutByVal(base.get(), property.get(), value);
     3449        generator.emitProfileType(value, divotStart(), divotEnd());
     3450    }
     3451}
     3452
     3453void AssignmentElementNode::toString(StringBuilder& builder) const
     3454{
     3455    if (m_assignmentTarget->isResolveNode())
     3456        builder.append(static_cast<ResolveNode*>(m_assignmentTarget)->identifier().string());
     3457}
     3458
    34013459RegisterID* SpreadExpressionNode::emitBytecode(BytecodeGenerator&, RegisterID*)
    34023460{
  • trunk/Source/JavaScriptCore/parser/ASTBuilder.h

    r192147 r192436  
    122122    typedef ObjectPatternNode* ObjectPattern;
    123123    typedef BindingNode* BindingPattern;
     124    typedef AssignmentElementNode* AssignmentElement;
    124125    static const bool CreatesAST = true;
    125126    static const bool NeedsFreeVariableInfo = true;
     
    525526    }
    526527
     528    bool isAssignmentLocation(const Expression& pattern)
     529    {
     530        return pattern->isAssignmentLocation();
     531    }
     532
     533    bool isObjectLiteral(const Expression& node)
     534    {
     535        return node->isObjectLiteral();
     536    }
     537
     538    bool isArrayLiteral(const Expression& node)
     539    {
     540        return node->isArrayLiteral();
     541    }
     542
     543    bool isObjectOrArrayLiteral(const Expression& node)
     544    {
     545        return isObjectLiteral(node) || isArrayLiteral(node);
     546    }
     547
    527548    StatementNode* createEmptyStatement(const JSTokenLocation& location) { return new (m_parserArena) EmptyStatementNode(location); }
    528549
     
    835856    {
    836857        return new (m_parserArena) BindingNode(boundProperty, start, end, context);
     858    }
     859
     860    AssignmentElement createAssignmentElement(const Expression& assignmentTarget, const JSTextPosition& start, const JSTextPosition& end)
     861    {
     862        return new (m_parserArena) AssignmentElementNode(assignmentTarget, start, end);
    837863    }
    838864
  • trunk/Source/JavaScriptCore/parser/NodeConstructors.h

    r192147 r192436  
    10211021    {
    10221022    }
    1023    
     1023
     1024    inline AssignmentElementNode::AssignmentElementNode(ExpressionNode* assignmentTarget, const JSTextPosition& start, const JSTextPosition& end)
     1025        : DestructuringPatternNode()
     1026        , m_divotStart(start)
     1027        , m_divotEnd(end)
     1028        , m_assignmentTarget(assignmentTarget)
     1029    {
     1030    }
     1031
    10241032    inline DestructuringAssignmentNode::DestructuringAssignmentNode(const JSTokenLocation& location, DestructuringPatternNode* bindings, ExpressionNode* initializer)
    10251033        : ExpressionNode(location)
  • trunk/Source/JavaScriptCore/parser/Nodes.h

    r192147 r192436  
    154154        virtual bool isNumber() const { return false; }
    155155        virtual bool isString() const { return false; }
     156        virtual bool isObjectLiteral() const { return false; }
     157        virtual bool isArrayLiteral() const { return false; }
    156158        virtual bool isNull() const { return false; }
    157159        virtual bool isPure(BytecodeGenerator&) const { return false; }       
     
    593595        ArrayNode(const JSTokenLocation&, int elision, ElementNode*);
    594596
     597        virtual bool isArrayLiteral() const override { return true; }
     598
    595599        ArgumentListNode* toArgumentList(ParserArena&, int, int) const;
    596600
     
    648652        ObjectLiteralNode(const JSTokenLocation&);
    649653        ObjectLiteralNode(const JSTokenLocation&, PropertyListNode*);
     654        virtual bool isObjectLiteral() const override { return true; }
    650655
    651656    private:
     
    20492054    };
    20502055
     2056    class AssignmentElementNode : public DestructuringPatternNode {
     2057    public:
     2058        AssignmentElementNode(ExpressionNode* assignmentTarget, const JSTextPosition& start, const JSTextPosition& end);
     2059        const ExpressionNode* assignmentTarget() { return m_assignmentTarget; }
     2060
     2061        const JSTextPosition& divotStart() const { return m_divotStart; }
     2062        const JSTextPosition& divotEnd() const { return m_divotEnd; }
     2063
     2064    private:
     2065        virtual void collectBoundIdentifiers(Vector<Identifier>&) const override;
     2066        virtual void bindValue(BytecodeGenerator&, RegisterID*) const override;
     2067        virtual void toString(StringBuilder&) const override;
     2068
     2069        JSTextPosition m_divotStart;
     2070        JSTextPosition m_divotEnd;
     2071        ExpressionNode* m_assignmentTarget;
     2072    };
     2073
    20512074    class DestructuringAssignmentNode : public ExpressionNode {
    20522075    public:
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r192147 r192436  
    732732
    733733template <typename LexerType>
     734template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern Parser<LexerType>::createAssignmentElement(TreeBuilder& context, TreeExpression& assignmentTarget, const JSTextPosition& startPosition, const JSTextPosition& endPosition)
     735{
     736    return context.createAssignmentElement(assignmentTarget, startPosition, endPosition);
     737}
     738
     739template <typename LexerType>
    734740template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseArrowFunctionSingleExpressionBodySourceElements(TreeBuilder& context)
    735741{
     
    764770{
    765771    return parseDestructuringPattern(context, DestructureToExpressions, ExportType::NotExported, nullptr, nullptr, bindingContext);
     772}
     773
     774template <typename LexerType>
     775template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseBindingOrAssignmentElement(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
     776{
     777    if (kind == DestructureToExpressions)
     778        return parseAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
     779    return parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
     780}
     781
     782template <typename LexerType>
     783template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseAssignmentElement(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
     784{
     785    SavePoint savePoint = createSavePoint();
     786    TreeDestructuringPattern assignmentTarget = 0;
     787
     788    if (match(OPENBRACE) || match(OPENBRACKET))
     789        assignmentTarget = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
     790    if (!assignmentTarget || match(DOT) || match(OPENBRACKET) || match(OPENPAREN) || match(TEMPLATE)) {
     791        restoreSavePoint(savePoint);
     792        JSTextPosition startPosition = tokenStartPosition();
     793        auto element = parseMemberExpression(context);
     794
     795        semanticFailIfFalse(element && context.isAssignmentLocation(element), "Invalid destructuring assignment target");
     796
     797        return createAssignmentElement(context, element, startPosition, lastTokenEndPosition());
     798    }
     799    return assignmentTarget;
    766800}
    767801
     
    796830                JSTokenLocation location = m_token.m_location;
    797831                next();
    798                 auto innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
     832                auto innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    799833                if (kind == DestructureToExpressions && !innerPattern)
    800834                    return 0;
     
    809843
    810844            JSTokenLocation location = m_token.m_location;
    811             auto innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
     845            auto innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    812846            if (kind == DestructureToExpressions && !innerPattern)
    813847                return 0;
     
    817851        } while (consume(COMMA));
    818852
    819         if (kind == DestructureToExpressions && !match(CLOSEBRACKET))
    820             return 0;
    821853        consumeOrFail(CLOSEBRACKET, restElementWasFound ? "Expected a closing ']' following a rest element destructuring pattern" : "Expected either a closing ']' or a ',' following an element destructuring pattern");
    822854        context.finishArrayPattern(arrayPattern, divotStart, divotStart, lastTokenEndPosition());
     
    846878                next();
    847879                if (consume(COLON))
    848                     innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
     880                    innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    849881                else
    850882                    innerPattern = createBindingPattern(context, kind, exportType, *propertyName, depth + 1, identifierToken, bindingContext, duplicateIdentifier);
     
    879911                    failWithMessage("Expected a ':' prior to a named destructuring property");
    880912                }
    881                 innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
     913                innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    882914            }
    883915            if (kind == DestructureToExpressions && !innerPattern)
     
    26902722    int initialAssignmentCount = m_assignmentCount;
    26912723    int initialNonLHSCount = m_nonLHSCount;
     2724    String assignmentPatternError = String();
    26922725    if (match(OPENBRACE) || match(OPENBRACKET)) {
    26932726        SavePoint savePoint = createSavePoint();
     
    26982731                return context.createDestructuringAssignment(location, pattern, rhs);
    26992732        }
     2733        assignmentPatternError = m_errorMessage;
    27002734        restoreSavePoint(savePoint);
    27012735    }
     
    27122746   
    27132747    TreeExpression lhs = parseConditionalExpression(context);
     2748    if (!assignmentPatternError.isNull() && (lhs && (context.isObjectOrArrayLiteral(lhs) && match(EQUAL)))) {
     2749        setErrorMessage(assignmentPatternError);
     2750        return 0;
     2751    }
    27142752    failIfFalse(lhs, "Cannot parse expression");
    27152753    if (initialNonLHSCount != m_nonLHSCount) {
  • trunk/Source/JavaScriptCore/parser/Parser.h

    r192147 r192436  
    11611161    template <class TreeBuilder> TreeExpression parseArrowFunctionExpression(TreeBuilder&);
    11621162    template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, ExportType, const Identifier&, int depth, JSToken, AssignmentContext, const Identifier** duplicateIdentifier);
     1163    template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createAssignmentElement(TreeBuilder&, TreeExpression&, const JSTextPosition&, const JSTextPosition&);
     1164    template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseBindingOrAssignmentElement(TreeBuilder& context, DestructuringKind, ExportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth);
     1165    template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseAssignmentElement(TreeBuilder& context, DestructuringKind, ExportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth);
    11631166    template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseDestructuringPattern(TreeBuilder&, DestructuringKind, ExportType, const Identifier** duplicateIdentifier = nullptr, bool* hasDestructuringPattern = nullptr, AssignmentContext = AssignmentContext::DeclarationStatement, int depth = 0);
    11641167    template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern tryParseDestructuringPatternExpression(TreeBuilder&, AssignmentContext);
  • trunk/Source/JavaScriptCore/parser/SyntaxChecker.h

    r192147 r192436  
    347347        return BindingDestructuring;
    348348    }
     349    DestructuringPattern createAssignmentElement(const Expression&, const JSTextPosition&, const JSTextPosition&)
     350    {
     351        return BindingDestructuring;
     352    }
    349353
    350354    bool isBindingNode(DestructuringPattern pattern)
    351355    {
    352356        return pattern == BindingDestructuring;
     357    }
     358
     359    bool isAssignmentLocation(ExpressionType type)
     360    {
     361        return type == ResolveExpr || type == DotExpr || type == BracketExpr;
     362    }
     363
     364    bool isObjectLiteral(ExpressionType type)
     365    {
     366        return type == ObjectLiteralExpr;
     367    }
     368
     369    bool isArrayLiteral(ExpressionType type)
     370    {
     371        return type == ArrayLiteralExpr;
     372    }
     373
     374    bool isObjectOrArrayLiteral(ExpressionType type)
     375    {
     376        return isObjectLiteral(type) || isArrayLiteral(type);
    353377    }
    354378
  • trunk/Source/JavaScriptCore/tests/es6.yaml

    r191864 r192436  
    215215- path: es6/destructuring_with_strings.js
    216216  cmd: runES6 :normal
     217- path: es6/destructuring_assignment_non_simple_target.js
     218  cmd: runES6 :normal
     219- path: es6/destructuring_initializer_scoping.js
     220  cmd: runES6 :normal
    217221- path: es6/for..of_loops_with_arrays.js
    218222  cmd: runES6 :normal
     
    748752  cmd: runES6 :fail
    749753- path: es6/destructuring_nested_rest.js
    750   cmd: runES6 :fail
     754  cmd: runES6 :normal
    751755- path: es6/destructuring_with_generator_instances.js
    752756  cmd: runES6 :fail
  • trunk/Source/JavaScriptCore/tests/stress/rest-elements.js

    r186246 r192436  
    110110testSyntaxError(String.raw`(function ([a, ...{ b, c }]) { })`, String.raw`SyntaxError: Unexpected token ']'. Expected identifier for a rest element destructuring pattern.`);
    111111
    112 shouldThrow(function () {
    113     [a, ...b, c] = 20;
    114 }, "ReferenceError: Left side of assignment is not a reference.");
    115 
    116 shouldThrow(function () {
    117     [a, ...b,] = 20
    118 }, "ReferenceError: Left side of assignment is not a reference.");
    119 
    120 shouldThrow(function () {
    121     [a, ...b,,] = 20
    122 }, "ReferenceError: Left side of assignment is not a reference.");
    123 
    124 shouldThrow(function () {
    125     [a, ...b = 20] = 20
    126 }, "ReferenceError: Left side of assignment is not a reference.");
     112
     113testSyntaxError(String.raw`[a, ...b, c] = 20`, String.raw`SyntaxError: Unexpected token ','. Expected a closing ']' following a rest element destructuring pattern.`);
     114testSyntaxError(String.raw`[a, ...b,] = 20`, String.raw`SyntaxError: Unexpected token ','. Expected a closing ']' following a rest element destructuring pattern.`);
     115testSyntaxError(String.raw`[a, ...b,,] = 20`, String.raw`SyntaxError: Unexpected token ','. Expected a closing ']' following a rest element destructuring pattern.`);
     116testSyntaxError(String.raw`[a, ...b = 20] = 20`, String.raw`SyntaxError: Unexpected token '='. Expected a closing ']' following a rest element destructuring pattern.`);
    127117
    128118(function () {
Note: See TracChangeset for help on using the changeset viewer.