<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[192436] trunk/Source/JavaScriptCore</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/192436">192436</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2015-11-13 11:13:39 -0800 (Fri, 13 Nov 2015)</dd>
</dl>
<h3>Log Message</h3>
<pre>Allow any LeftHandSideExpression as a valid AssignmentElement
https://bugs.webkit.org/show_bug.cgi?id=151026
Patch by Caitlin Potter <caitpotter88@gmail.com> 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):</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerNodesCodegencpp">trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserASTBuilderh">trunk/Source/JavaScriptCore/parser/ASTBuilder.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserNodeConstructorsh">trunk/Source/JavaScriptCore/parser/NodeConstructors.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserNodesh">trunk/Source/JavaScriptCore/parser/Nodes.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserParsercpp">trunk/Source/JavaScriptCore/parser/Parser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserParserh">trunk/Source/JavaScriptCore/parser/Parser.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserSyntaxCheckerh">trunk/Source/JavaScriptCore/parser/SyntaxChecker.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretestses6yaml">trunk/Source/JavaScriptCore/tests/es6.yaml</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressrestelementsjs">trunk/Source/JavaScriptCore/tests/stress/rest-elements.js</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestses6destructuring_assignment_non_simple_targetjs">trunk/Source/JavaScriptCore/tests/es6/destructuring_assignment_non_simple_target.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestses6destructuring_initializer_scopingjs">trunk/Source/JavaScriptCore/tests/es6/destructuring_initializer_scoping.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressdestructuringassignmentsyntaxjs">trunk/Source/JavaScriptCore/tests/stress/destructuring-assignment-syntax.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (192435 => 192436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-11-13 19:10:23 UTC (rev 192435)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-11-13 19:13:39 UTC (rev 192436)
</span><span class="lines">@@ -1,3 +1,30 @@
</span><ins>+2015-11-13 Caitlin Potter <caitpotter88@gmail.com>
+
+ Allow any LeftHandSideExpression as a valid AssignmentElement
+ https://bugs.webkit.org/show_bug.cgi?id=151026
+
+ 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):
+
</ins><span class="cx"> 2015-11-13 Yusuke Suzuki <utatane.tea@gmail.com>
</span><span class="cx">
</span><span class="cx"> op_assert should declare that it uses the first register argument
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerNodesCodegencpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (192435 => 192436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2015-11-13 19:10:23 UTC (rev 192435)
+++ trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2015-11-13 19:13:39 UTC (rev 192436)
</span><span class="lines">@@ -3397,7 +3397,65 @@
</span><span class="cx"> {
</span><span class="cx"> identifiers.append(m_boundProperty);
</span><span class="cx"> }
</span><del>-
</del><ins>+
+void AssignmentElementNode::collectBoundIdentifiers(Vector<Identifier>&) const
+{
+}
+
+void AssignmentElementNode::bindValue(BytecodeGenerator& generator, RegisterID* value) const
+{
+ if (m_assignmentTarget->isResolveNode()) {
+ ResolveNode* lhs = static_cast<ResolveNode*>(m_assignmentTarget);
+ Variable var = generator.variable(lhs->identifier());
+ bool isReadOnly = var.isReadOnly();
+ if (RegisterID* local = var.local()) {
+ generator.emitTDZCheckIfNecessary(var, local, nullptr);
+
+ if (isReadOnly)
+ generator.emitReadOnlyExceptionIfNeeded(var);
+ else {
+ generator.invalidateForInContextForLocal(local);
+ generator.moveToDestinationIfNeeded(local, value);
+ generator.emitProfileType(local, divotStart(), divotEnd());
+ }
+ return;
+ }
+ if (generator.isStrictMode())
+ generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
+ RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
+ generator.emitTDZCheckIfNecessary(var, nullptr, scope.get());
+ if (isReadOnly) {
+ bool threwException = generator.emitReadOnlyExceptionIfNeeded(var);
+ if (threwException)
+ return;
+ }
+ generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
+ if (!isReadOnly) {
+ generator.emitPutToScope(scope.get(), var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, NotInitialization);
+ generator.emitProfileType(value, var, divotStart(), divotEnd());
+ }
+ } else if (m_assignmentTarget->isDotAccessorNode()) {
+ DotAccessorNode* lhs = static_cast<DotAccessorNode*>(m_assignmentTarget);
+ RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(lhs->base(), true, false);
+ generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
+ generator.emitPutById(base.get(), lhs->identifier(), value);
+ generator.emitProfileType(value, divotStart(), divotEnd());
+ } else if (m_assignmentTarget->isBracketAccessorNode()) {
+ BracketAccessorNode* lhs = static_cast<BracketAccessorNode*>(m_assignmentTarget);
+ RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(lhs->base(), true, false);
+ RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(lhs->subscript(), true, false);
+ generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
+ generator.emitPutByVal(base.get(), property.get(), value);
+ generator.emitProfileType(value, divotStart(), divotEnd());
+ }
+}
+
+void AssignmentElementNode::toString(StringBuilder& builder) const
+{
+ if (m_assignmentTarget->isResolveNode())
+ builder.append(static_cast<ResolveNode*>(m_assignmentTarget)->identifier().string());
+}
+
</ins><span class="cx"> RegisterID* SpreadExpressionNode::emitBytecode(BytecodeGenerator&, RegisterID*)
</span><span class="cx"> {
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserASTBuilderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/ASTBuilder.h (192435 => 192436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/ASTBuilder.h        2015-11-13 19:10:23 UTC (rev 192435)
+++ trunk/Source/JavaScriptCore/parser/ASTBuilder.h        2015-11-13 19:13:39 UTC (rev 192436)
</span><span class="lines">@@ -121,6 +121,7 @@
</span><span class="cx"> typedef ArrayPatternNode* ArrayPattern;
</span><span class="cx"> typedef ObjectPatternNode* ObjectPattern;
</span><span class="cx"> typedef BindingNode* BindingPattern;
</span><ins>+ typedef AssignmentElementNode* AssignmentElement;
</ins><span class="cx"> static const bool CreatesAST = true;
</span><span class="cx"> static const bool NeedsFreeVariableInfo = true;
</span><span class="cx"> static const bool CanUseFunctionCache = true;
</span><span class="lines">@@ -524,6 +525,26 @@
</span><span class="cx"> return pattern->isBindingNode();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ bool isAssignmentLocation(const Expression& pattern)
+ {
+ return pattern->isAssignmentLocation();
+ }
+
+ bool isObjectLiteral(const Expression& node)
+ {
+ return node->isObjectLiteral();
+ }
+
+ bool isArrayLiteral(const Expression& node)
+ {
+ return node->isArrayLiteral();
+ }
+
+ bool isObjectOrArrayLiteral(const Expression& node)
+ {
+ return isObjectLiteral(node) || isArrayLiteral(node);
+ }
+
</ins><span class="cx"> StatementNode* createEmptyStatement(const JSTokenLocation& location) { return new (m_parserArena) EmptyStatementNode(location); }
</span><span class="cx">
</span><span class="cx"> StatementNode* createDeclarationStatement(const JSTokenLocation& location, ExpressionNode* expr, int start, int end)
</span><span class="lines">@@ -836,6 +857,11 @@
</span><span class="cx"> return new (m_parserArena) BindingNode(boundProperty, start, end, context);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ AssignmentElement createAssignmentElement(const Expression& assignmentTarget, const JSTextPosition& start, const JSTextPosition& end)
+ {
+ return new (m_parserArena) AssignmentElementNode(assignmentTarget, start, end);
+ }
+
</ins><span class="cx"> void setEndOffset(Node* node, int offset)
</span><span class="cx"> {
</span><span class="cx"> node->setEndOffset(offset);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserNodeConstructorsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/NodeConstructors.h (192435 => 192436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/NodeConstructors.h        2015-11-13 19:10:23 UTC (rev 192435)
+++ trunk/Source/JavaScriptCore/parser/NodeConstructors.h        2015-11-13 19:13:39 UTC (rev 192436)
</span><span class="lines">@@ -1020,7 +1020,15 @@
</span><span class="cx"> , m_bindingContext(context)
</span><span class="cx"> {
</span><span class="cx"> }
</span><del>-
</del><ins>+
+ inline AssignmentElementNode::AssignmentElementNode(ExpressionNode* assignmentTarget, const JSTextPosition& start, const JSTextPosition& end)
+ : DestructuringPatternNode()
+ , m_divotStart(start)
+ , m_divotEnd(end)
+ , m_assignmentTarget(assignmentTarget)
+ {
+ }
+
</ins><span class="cx"> inline DestructuringAssignmentNode::DestructuringAssignmentNode(const JSTokenLocation& location, DestructuringPatternNode* bindings, ExpressionNode* initializer)
</span><span class="cx"> : ExpressionNode(location)
</span><span class="cx"> , m_bindings(bindings)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserNodesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Nodes.h (192435 => 192436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Nodes.h        2015-11-13 19:10:23 UTC (rev 192435)
+++ trunk/Source/JavaScriptCore/parser/Nodes.h        2015-11-13 19:13:39 UTC (rev 192436)
</span><span class="lines">@@ -153,6 +153,8 @@
</span><span class="cx">
</span><span class="cx"> virtual bool isNumber() const { return false; }
</span><span class="cx"> virtual bool isString() const { return false; }
</span><ins>+ virtual bool isObjectLiteral() const { return false; }
+ virtual bool isArrayLiteral() const { return false; }
</ins><span class="cx"> virtual bool isNull() const { return false; }
</span><span class="cx"> virtual bool isPure(BytecodeGenerator&) const { return false; }
</span><span class="cx"> virtual bool isConstant() const { return false; }
</span><span class="lines">@@ -592,6 +594,8 @@
</span><span class="cx"> ArrayNode(const JSTokenLocation&, ElementNode*);
</span><span class="cx"> ArrayNode(const JSTokenLocation&, int elision, ElementNode*);
</span><span class="cx">
</span><ins>+ virtual bool isArrayLiteral() const override { return true; }
+
</ins><span class="cx"> ArgumentListNode* toArgumentList(ParserArena&, int, int) const;
</span><span class="cx">
</span><span class="cx"> ElementNode* elements() const { ASSERT(isSimpleArray()); return m_element; }
</span><span class="lines">@@ -647,6 +651,7 @@
</span><span class="cx"> public:
</span><span class="cx"> ObjectLiteralNode(const JSTokenLocation&);
</span><span class="cx"> ObjectLiteralNode(const JSTokenLocation&, PropertyListNode*);
</span><ins>+ virtual bool isObjectLiteral() const override { return true; }
</ins><span class="cx">
</span><span class="cx"> private:
</span><span class="cx"> virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
</span><span class="lines">@@ -2048,6 +2053,24 @@
</span><span class="cx"> AssignmentContext m_bindingContext;
</span><span class="cx"> };
</span><span class="cx">
</span><ins>+ class AssignmentElementNode : public DestructuringPatternNode {
+ public:
+ AssignmentElementNode(ExpressionNode* assignmentTarget, const JSTextPosition& start, const JSTextPosition& end);
+ const ExpressionNode* assignmentTarget() { return m_assignmentTarget; }
+
+ const JSTextPosition& divotStart() const { return m_divotStart; }
+ const JSTextPosition& divotEnd() const { return m_divotEnd; }
+
+ private:
+ virtual void collectBoundIdentifiers(Vector<Identifier>&) const override;
+ virtual void bindValue(BytecodeGenerator&, RegisterID*) const override;
+ virtual void toString(StringBuilder&) const override;
+
+ JSTextPosition m_divotStart;
+ JSTextPosition m_divotEnd;
+ ExpressionNode* m_assignmentTarget;
+ };
+
</ins><span class="cx"> class DestructuringAssignmentNode : public ExpressionNode {
</span><span class="cx"> public:
</span><span class="cx"> DestructuringAssignmentNode(const JSTokenLocation&, DestructuringPatternNode*, ExpressionNode*);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Parser.cpp (192435 => 192436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Parser.cpp        2015-11-13 19:10:23 UTC (rev 192435)
+++ trunk/Source/JavaScriptCore/parser/Parser.cpp        2015-11-13 19:13:39 UTC (rev 192436)
</span><span class="lines">@@ -731,6 +731,12 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template <typename LexerType>
</span><ins>+template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern Parser<LexerType>::createAssignmentElement(TreeBuilder& context, TreeExpression& assignmentTarget, const JSTextPosition& startPosition, const JSTextPosition& endPosition)
+{
+ return context.createAssignmentElement(assignmentTarget, startPosition, endPosition);
+}
+
+template <typename LexerType>
</ins><span class="cx"> template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseArrowFunctionSingleExpressionBodySourceElements(TreeBuilder& context)
</span><span class="cx"> {
</span><span class="cx"> ASSERT(!match(OPENBRACE));
</span><span class="lines">@@ -766,6 +772,34 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template <typename LexerType>
</span><ins>+template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseBindingOrAssignmentElement(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
+{
+ if (kind == DestructureToExpressions)
+ return parseAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
+ return parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseAssignmentElement(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
+{
+ SavePoint savePoint = createSavePoint();
+ TreeDestructuringPattern assignmentTarget = 0;
+
+ if (match(OPENBRACE) || match(OPENBRACKET))
+ assignmentTarget = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
+ if (!assignmentTarget || match(DOT) || match(OPENBRACKET) || match(OPENPAREN) || match(TEMPLATE)) {
+ restoreSavePoint(savePoint);
+ JSTextPosition startPosition = tokenStartPosition();
+ auto element = parseMemberExpression(context);
+
+ semanticFailIfFalse(element && context.isAssignmentLocation(element), "Invalid destructuring assignment target");
+
+ return createAssignmentElement(context, element, startPosition, lastTokenEndPosition());
+ }
+ return assignmentTarget;
+}
+
+template <typename LexerType>
</ins><span class="cx"> template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDestructuringPattern(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
</span><span class="cx"> {
</span><span class="cx"> failIfStackOverflow();
</span><span class="lines">@@ -795,7 +829,7 @@
</span><span class="cx"> if (UNLIKELY(match(DOTDOTDOT))) {
</span><span class="cx"> JSTokenLocation location = m_token.m_location;
</span><span class="cx"> next();
</span><del>- auto innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
</del><ins>+ auto innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
</ins><span class="cx"> if (kind == DestructureToExpressions && !innerPattern)
</span><span class="cx"> return 0;
</span><span class="cx"> failIfFalse(innerPattern, "Cannot parse this destructuring pattern");
</span><span class="lines">@@ -808,7 +842,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> JSTokenLocation location = m_token.m_location;
</span><del>- auto innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
</del><ins>+ auto innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
</ins><span class="cx"> if (kind == DestructureToExpressions && !innerPattern)
</span><span class="cx"> return 0;
</span><span class="cx"> failIfFalse(innerPattern, "Cannot parse this destructuring pattern");
</span><span class="lines">@@ -816,8 +850,6 @@
</span><span class="cx"> context.appendArrayPatternEntry(arrayPattern, location, innerPattern, defaultValue);
</span><span class="cx"> } while (consume(COMMA));
</span><span class="cx">
</span><del>- if (kind == DestructureToExpressions && !match(CLOSEBRACKET))
- return 0;
</del><span class="cx"> consumeOrFail(CLOSEBRACKET, restElementWasFound ? "Expected a closing ']' following a rest element destructuring pattern" : "Expected either a closing ']' or a ',' following an element destructuring pattern");
</span><span class="cx"> context.finishArrayPattern(arrayPattern, divotStart, divotStart, lastTokenEndPosition());
</span><span class="cx"> pattern = arrayPattern;
</span><span class="lines">@@ -845,7 +877,7 @@
</span><span class="cx"> JSToken identifierToken = m_token;
</span><span class="cx"> next();
</span><span class="cx"> if (consume(COLON))
</span><del>- innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
</del><ins>+ innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
</ins><span class="cx"> else
</span><span class="cx"> innerPattern = createBindingPattern(context, kind, exportType, *propertyName, depth + 1, identifierToken, bindingContext, duplicateIdentifier);
</span><span class="cx"> } else {
</span><span class="lines">@@ -878,7 +910,7 @@
</span><span class="cx">
</span><span class="cx"> failWithMessage("Expected a ':' prior to a named destructuring property");
</span><span class="cx"> }
</span><del>- innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
</del><ins>+ innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
</ins><span class="cx"> }
</span><span class="cx"> if (kind == DestructureToExpressions && !innerPattern)
</span><span class="cx"> return 0;
</span><span class="lines">@@ -2689,6 +2721,7 @@
</span><span class="cx"> JSTokenLocation location(tokenLocation());
</span><span class="cx"> int initialAssignmentCount = m_assignmentCount;
</span><span class="cx"> int initialNonLHSCount = m_nonLHSCount;
</span><ins>+ String assignmentPatternError = String();
</ins><span class="cx"> if (match(OPENBRACE) || match(OPENBRACKET)) {
</span><span class="cx"> SavePoint savePoint = createSavePoint();
</span><span class="cx"> auto pattern = tryParseDestructuringPatternExpression(context, AssignmentContext::AssignmentExpression);
</span><span class="lines">@@ -2697,6 +2730,7 @@
</span><span class="cx"> if (rhs)
</span><span class="cx"> return context.createDestructuringAssignment(location, pattern, rhs);
</span><span class="cx"> }
</span><ins>+ assignmentPatternError = m_errorMessage;
</ins><span class="cx"> restoreSavePoint(savePoint);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -2711,6 +2745,10 @@
</span><span class="cx"> #endif
</span><span class="cx">
</span><span class="cx"> TreeExpression lhs = parseConditionalExpression(context);
</span><ins>+ if (!assignmentPatternError.isNull() && (lhs && (context.isObjectOrArrayLiteral(lhs) && match(EQUAL)))) {
+ setErrorMessage(assignmentPatternError);
+ return 0;
+ }
</ins><span class="cx"> failIfFalse(lhs, "Cannot parse expression");
</span><span class="cx"> if (initialNonLHSCount != m_nonLHSCount) {
</span><span class="cx"> if (m_token.m_type >= EQUAL && m_token.m_type <= OREQUAL)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Parser.h (192435 => 192436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Parser.h        2015-11-13 19:10:23 UTC (rev 192435)
+++ trunk/Source/JavaScriptCore/parser/Parser.h        2015-11-13 19:13:39 UTC (rev 192436)
</span><span class="lines">@@ -1160,6 +1160,9 @@
</span><span class="cx"> template <class TreeBuilder> TreeSourceElements parseArrowFunctionSingleExpressionBodySourceElements(TreeBuilder&);
</span><span class="cx"> template <class TreeBuilder> TreeExpression parseArrowFunctionExpression(TreeBuilder&);
</span><span class="cx"> template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, ExportType, const Identifier&, int depth, JSToken, AssignmentContext, const Identifier** duplicateIdentifier);
</span><ins>+ template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createAssignmentElement(TreeBuilder&, TreeExpression&, const JSTextPosition&, const JSTextPosition&);
+ template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseBindingOrAssignmentElement(TreeBuilder& context, DestructuringKind, ExportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth);
+ template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseAssignmentElement(TreeBuilder& context, DestructuringKind, ExportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth);
</ins><span class="cx"> template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseDestructuringPattern(TreeBuilder&, DestructuringKind, ExportType, const Identifier** duplicateIdentifier = nullptr, bool* hasDestructuringPattern = nullptr, AssignmentContext = AssignmentContext::DeclarationStatement, int depth = 0);
</span><span class="cx"> template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern tryParseDestructuringPatternExpression(TreeBuilder&, AssignmentContext);
</span><span class="cx"> template <class TreeBuilder> NEVER_INLINE TreeExpression parseDefaultValueForDestructuringPattern(TreeBuilder&);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserSyntaxCheckerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/SyntaxChecker.h (192435 => 192436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/SyntaxChecker.h        2015-11-13 19:10:23 UTC (rev 192435)
+++ trunk/Source/JavaScriptCore/parser/SyntaxChecker.h        2015-11-13 19:13:39 UTC (rev 192436)
</span><span class="lines">@@ -346,12 +346,36 @@
</span><span class="cx"> {
</span><span class="cx"> return BindingDestructuring;
</span><span class="cx"> }
</span><ins>+ DestructuringPattern createAssignmentElement(const Expression&, const JSTextPosition&, const JSTextPosition&)
+ {
+ return BindingDestructuring;
+ }
</ins><span class="cx">
</span><span class="cx"> bool isBindingNode(DestructuringPattern pattern)
</span><span class="cx"> {
</span><span class="cx"> return pattern == BindingDestructuring;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ bool isAssignmentLocation(ExpressionType type)
+ {
+ return type == ResolveExpr || type == DotExpr || type == BracketExpr;
+ }
+
+ bool isObjectLiteral(ExpressionType type)
+ {
+ return type == ObjectLiteralExpr;
+ }
+
+ bool isArrayLiteral(ExpressionType type)
+ {
+ return type == ArrayLiteralExpr;
+ }
+
+ bool isObjectOrArrayLiteral(ExpressionType type)
+ {
+ return isObjectLiteral(type) || isArrayLiteral(type);
+ }
+
</ins><span class="cx"> void setEndOffset(int, int) { }
</span><span class="cx"> int endOffset(int) { return 0; }
</span><span class="cx"> void setStartOffset(int, int) { }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestses6destructuring_assignment_non_simple_targetjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/es6/destructuring_assignment_non_simple_target.js (0 => 192436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/es6/destructuring_assignment_non_simple_target.js         (rev 0)
+++ trunk/Source/JavaScriptCore/tests/es6/destructuring_assignment_non_simple_target.js        2015-11-13 19:13:39 UTC (rev 192436)
</span><span class="lines">@@ -0,0 +1,16 @@
</span><ins>+function test() {
+ var msg = {};
+ ({
+ name: msg.name,
+ "parameters": [msg.callback, ...msg["parameters"]],
+ 0: msg[0]
+ } = {
+ name: "test",
+ parameters: [function cb() { return "test"; }, "a", "b", "c"],
+ "0": NaN
+ });
+ return msg.name === "test" && msg[0] !== msg[0] && msg.callback() === "test" && (msg.parameters + "") === "a,b,c";
+}
+
+if (!test())
+ throw new Error("Test failed");
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestses6destructuring_initializer_scopingjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/es6/destructuring_initializer_scoping.js (0 => 192436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/es6/destructuring_initializer_scoping.js         (rev 0)
+++ trunk/Source/JavaScriptCore/tests/es6/destructuring_initializer_scoping.js        2015-11-13 19:13:39 UTC (rev 192436)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+var outer = [];
+function test() {
+ var a = {};
+ var defaultObj = {
+ name: "default",
+ length: 3,
+ 0: "a",
+ 1: "b",
+ 2: "c",
+ [Symbol.iterator]: Array.prototype[Symbol.iterator]
+ };
+ function tester({ name } = { name: a.name } = [outer[0], ...outer[1]] = defaultObj) { return name; }
+ return tester() === "default" && a.name === "default" && (outer + "") === "a,b,c";
+}
+
+if (!test())
+ throw new Error("Test failed");
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestses6yaml"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/tests/es6.yaml (192435 => 192436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/es6.yaml        2015-11-13 19:10:23 UTC (rev 192435)
+++ trunk/Source/JavaScriptCore/tests/es6.yaml        2015-11-13 19:13:39 UTC (rev 192436)
</span><span class="lines">@@ -214,6 +214,10 @@
</span><span class="cx"> cmd: runES6 :normal
</span><span class="cx"> - path: es6/destructuring_with_strings.js
</span><span class="cx"> cmd: runES6 :normal
</span><ins>+- path: es6/destructuring_assignment_non_simple_target.js
+ cmd: runES6 :normal
+- path: es6/destructuring_initializer_scoping.js
+ cmd: runES6 :normal
</ins><span class="cx"> - path: es6/for..of_loops_with_arrays.js
</span><span class="cx"> cmd: runES6 :normal
</span><span class="cx"> - path: es6/for..of_loops_with_astral_plane_strings.js
</span><span class="lines">@@ -747,7 +751,7 @@
</span><span class="cx"> - path: es6/destructuring_iterator_closing.js
</span><span class="cx"> cmd: runES6 :fail
</span><span class="cx"> - path: es6/destructuring_nested_rest.js
</span><del>- cmd: runES6 :fail
</del><ins>+ cmd: runES6 :normal
</ins><span class="cx"> - path: es6/destructuring_with_generator_instances.js
</span><span class="cx"> cmd: runES6 :fail
</span><span class="cx"> - path: es6/destructuring_with_generic_iterables.js
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressdestructuringassignmentsyntaxjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/destructuring-assignment-syntax.js (0 => 192436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/destructuring-assignment-syntax.js         (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/destructuring-assignment-syntax.js        2015-11-13 19:13:39 UTC (rev 192436)
</span><span class="lines">@@ -0,0 +1,59 @@
</span><ins>+
+function testSyntax(script) {
+ try {
+ eval(script);
+ } catch (error) {
+ if (error instanceof SyntaxError)
+ throw new Error("Bad error: " + String(error));
+ }
+}
+
+function testSyntaxError(script, message) {
+ var error = null;
+ try {
+ eval(script);
+ } catch (e) {
+ error = e;
+ }
+ if (!error)
+ throw new Error("Expected syntax error not thrown");
+
+ if (String(error) !== message)
+ throw new Error("Bad error: " + String(error));
+}
+
+testSyntax("({ a: this.a } = {})");
+testSyntax("({ a: this['a'] } = {})");
+testSyntax("({ a: this[\"a\"] } = {})");
+testSyntax("[this.a ] = []");
+testSyntax("[this['a']] = []");
+testSyntax("[this[0]] = []");
+testSyntax("[...this[0]] = []");
+testSyntax("[...[function f() {}.prop]] = []");
+testSyntax("[...[{prop: 1}.prop]] = []");
+testSyntax("[...[this[0], ...this[1]]] = []");
+testSyntax("({ a: obj.a } = {})");
+testSyntax("({ a: obj['a'] } = {})");
+testSyntax("({ a: obj[\"a\"] } = {})");
+testSyntax("({ a: function() {}['prop'] } = {})");
+testSyntax("({ a: {prop: 1}.prop } = {})");
+testSyntax("[obj.a ] = []");
+testSyntax("[obj['a']] = []");
+testSyntax("[obj[0]] = []");
+testSyntax("[function(){}.prop] = []");
+testSyntax("[{prop: 1}.prop] = []");
+
+
+testSyntaxError("[...c = 1] = []", "SyntaxError: Unexpected token '='. Expected a closing ']' following a rest element destructuring pattern.");
+testSyntaxError("[...c, d] = []", "SyntaxError: Unexpected token ','. Expected a closing ']' following a rest element destructuring pattern.");
+testSyntaxError("[this] = []", "SyntaxError: Invalid destructuring assignment target.");
+testSyntaxError("[th\\u{69}s] = []", "SyntaxError: Invalid destructuring assignment target.");
+testSyntaxError("[function() {}] = []", "SyntaxError: Invalid destructuring assignment target.");
+testSyntaxError("['string'] = []", "SyntaxError: Invalid destructuring assignment target.");
+testSyntaxError("[123] = []", "SyntaxError: Invalid destructuring assignment target.");
+testSyntaxError("[true] = []", "SyntaxError: Invalid destructuring assignment target.");
+testSyntaxError("[tru\\u0065] = []", "SyntaxError: Invalid destructuring assignment target.");
+testSyntaxError("[false] = []", "SyntaxError: Invalid destructuring assignment target.");
+testSyntaxError("[f\\u0061lse] = []", "SyntaxError: Invalid destructuring assignment target.");
+testSyntaxError("[null] = []", "SyntaxError: Invalid destructuring assignment target.");
+testSyntaxError("[n\\u{75}ll] = []", "SyntaxError: Invalid destructuring assignment target.");
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressrestelementsjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/tests/stress/rest-elements.js (192435 => 192436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/rest-elements.js        2015-11-13 19:10:23 UTC (rev 192435)
+++ trunk/Source/JavaScriptCore/tests/stress/rest-elements.js        2015-11-13 19:13:39 UTC (rev 192436)
</span><span class="lines">@@ -109,22 +109,12 @@
</span><span class="cx"> testSyntaxError(String.raw`(function ([a, ...[b, c]]) { })`, String.raw`SyntaxError: Unexpected token ']'. Expected identifier for a rest element destructuring pattern.`);
</span><span class="cx"> testSyntaxError(String.raw`(function ([a, ...{ b, c }]) { })`, String.raw`SyntaxError: Unexpected token ']'. Expected identifier for a rest element destructuring pattern.`);
</span><span class="cx">
</span><del>-shouldThrow(function () {
- [a, ...b, c] = 20;
-}, "ReferenceError: Left side of assignment is not a reference.");
</del><span class="cx">
</span><del>-shouldThrow(function () {
- [a, ...b,] = 20
-}, "ReferenceError: Left side of assignment is not a reference.");
</del><ins>+testSyntaxError(String.raw`[a, ...b, c] = 20`, String.raw`SyntaxError: Unexpected token ','. Expected a closing ']' following a rest element destructuring pattern.`);
+testSyntaxError(String.raw`[a, ...b,] = 20`, String.raw`SyntaxError: Unexpected token ','. Expected a closing ']' following a rest element destructuring pattern.`);
+testSyntaxError(String.raw`[a, ...b,,] = 20`, String.raw`SyntaxError: Unexpected token ','. Expected a closing ']' following a rest element destructuring pattern.`);
+testSyntaxError(String.raw`[a, ...b = 20] = 20`, String.raw`SyntaxError: Unexpected token '='. Expected a closing ']' following a rest element destructuring pattern.`);
</ins><span class="cx">
</span><del>-shouldThrow(function () {
- [a, ...b,,] = 20
-}, "ReferenceError: Left side of assignment is not a reference.");
-
-shouldThrow(function () {
- [a, ...b = 20] = 20
-}, "ReferenceError: Left side of assignment is not a reference.");
-
</del><span class="cx"> (function () {
</span><span class="cx"> var a, b, c;
</span><span class="cx"> [a, b, ...[...c]] = "Cocoa";
</span></span></pre>
</div>
</div>
</body>
</html>