Diff
Modified: trunk/LayoutTests/ChangeLog (159138 => 159139)
--- trunk/LayoutTests/ChangeLog 2013-11-12 20:50:45 UTC (rev 159138)
+++ trunk/LayoutTests/ChangeLog 2013-11-12 20:55:29 UTC (rev 159139)
@@ -1,3 +1,20 @@
+2013-11-11 Oliver Hunt <[email protected]>
+
+ Support unprefixed deconstructing assignment
+ https://bugs.webkit.org/show_bug.cgi?id=124172
+
+ Reviewed by Mark Lam.
+
+ Add and expand testing of destructuring assignment
+
+ * js/basic-for-of-expected.txt:
+ * js/destructuring-assignment-expected.txt:
+ * js/parser-syntax-check-expected.txt:
+ * js/script-tests/basic-for-of.js:
+ * js/script-tests/destructuring-assignment.js:
+ (testDestructuring):
+ * js/script-tests/parser-syntax-check.js:
+
2013-11-12 Roger Fong <[email protected]>
[Windows] Unreviewed gardening of some media tests.
Modified: trunk/LayoutTests/js/basic-for-of-expected.txt (159138 => 159139)
--- trunk/LayoutTests/js/basic-for-of-expected.txt 2013-11-12 20:50:45 UTC (rev 159138)
+++ trunk/LayoutTests/js/basic-for-of-expected.txt 2013-11-12 20:55:29 UTC (rev 159139)
@@ -63,6 +63,33 @@
PASS value is testArray[key]
PASS key is i
PASS testArray.length is 9
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS testArray.length is 13
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/js/destructuring-assignment-expected.txt (159138 => 159139)
--- trunk/LayoutTests/js/destructuring-assignment-expected.txt 2013-11-12 20:50:45 UTC (rev 159138)
+++ trunk/LayoutTests/js/destructuring-assignment-expected.txt 2013-11-12 20:55:29 UTC (rev 159139)
@@ -7,58 +7,75 @@
Function as String: (function([a,b]) { return a+b;})
PASS (function([a,b]) { return a+b;})(['1','2']) is '12'
PASS (function ([a,b]) { return a+b;})(['1','2']) is '12'
+PASS ([a,b]=['1','2']); var r=a+b; r is '12'
+PASS [a,b]=['1','2']; var r=a+b; r is '12'
PASS var {a,b}={a:'1',b:'2'}; var r=a+b; r is '12'
Function as String: (function({a,b}) { return a+b;})
PASS (function({a,b}) { return a+b;})({a:'1',b:'2'}) is '12'
PASS (function ({a:a,b:b}) { return a+b;})({a:'1',b:'2'}) is '12'
+PASS ({a,b}={a:'1',b:'2'}); var r=a+b; r is '12'
PASS var {c:a,d:b}={c:'1',d:'2'}; var r=a+b; r is '12'
Function as String: (function({c:a,d:b}) { return a+b;})
PASS (function({c:a,d:b}) { return a+b;})({c:'1',d:'2'}) is '12'
PASS (function ({c:a,d:b}) { return a+b;})({c:'1',d:'2'}) is '12'
+PASS ({c:a,d:b}={c:'1',d:'2'}); var r=a+b; r is '12'
PASS var {c:b,d:a}={c:'1',d:'2'}; var r=a+b; r is '21'
Function as String: (function({c:b,d:a}) { return a+b;})
PASS (function({c:b,d:a}) { return a+b;})({c:'1',d:'2'}) is '21'
PASS (function ({c:b,d:a}) { return a+b;})({c:'1',d:'2'}) is '21'
+PASS ({c:b,d:a}={c:'1',d:'2'}); var r=a+b; r is '21'
PASS var {true:a,false:b,undefined:c,null:d,in:e,for:f,1.5:g,'foo bar':h}={true:'a',false:'b',undefined:'c',null:'d',in:'e',for:'f',1.5:'g','foo bar':'h'}; var r=a+b+c+d+e+f+g+h; r is 'abcdefgh'
Function as String: (function({true:a,false:b,undefined:c,null:d,in:e,for:f,1.5:g,'foo bar':h}) { return a+b+c+d+e+f+g+h;})
PASS (function({true:a,false:b,undefined:c,null:d,in:e,for:f,1.5:g,'foo bar':h}) { return a+b+c+d+e+f+g+h;})({true:'a',false:'b',undefined:'c',null:'d',in:'e',for:'f',1.5:'g','foo bar':'h'}) is 'abcdefgh'
PASS (function ({true:a,false:b,undefined:c,null:d,in:e,for:f,1.5:g,"foo bar":h}) { return a+b+c+d+e+f+g+h;})({true:'a',false:'b',undefined:'c',null:'d',in:'e',for:'f',1.5:'g','foo bar':'h'}) is 'abcdefgh'
+PASS ({true:a,false:b,undefined:c,null:d,in:e,for:f,1.5:g,'foo bar':h}={true:'a',false:'b',undefined:'c',null:'d',in:'e',for:'f',1.5:'g','foo bar':'h'}); var r=a+b+c+d+e+f+g+h; r is 'abcdefgh'
PASS var [{c:a,d:b}]=[{c:'1',d:'2'}]; var r=a+b; r is '12'
Function as String: (function([{c:a,d:b}]) { return a+b;})
PASS (function([{c:a,d:b}]) { return a+b;})([{c:'1',d:'2'}]) is '12'
PASS (function ([{c:a,d:b}]) { return a+b;})([{c:'1',d:'2'}]) is '12'
+PASS ([{c:a,d:b}]=[{c:'1',d:'2'}]); var r=a+b; r is '12'
+PASS [{c:a,d:b}]=[{c:'1',d:'2'}]; var r=a+b; r is '12'
PASS var {x:[{c:a,d:b}]}={x:[{c:'1',d:'2'}]}; var r=a+b; r is '12'
Function as String: (function({x:[{c:a,d:b}]}) { return a+b;})
PASS (function({x:[{c:a,d:b}]}) { return a+b;})({x:[{c:'1',d:'2'}]}) is '12'
PASS (function ({x:[{c:a,d:b}]}) { return a+b;})({x:[{c:'1',d:'2'}]}) is '12'
+PASS ({x:[{c:a,d:b}]}={x:[{c:'1',d:'2'}]}); var r=a+b; r is '12'
PASS var [a,b]=anArray; var r=a+b; r is '12'
Function as String: (function([a,b]) { return a+b;})
PASS (function([a,b]) { return a+b;})(anArray) is '12'
PASS (function ([a,b]) { return a+b;})(anArray) is '12'
+PASS ([a,b]=anArray); var r=a+b; r is '12'
+PASS [a,b]=anArray; var r=a+b; r is '12'
PASS var {a,b}=anArray; var r=a+b; r is '34'
Function as String: (function({a,b}) { return a+b;})
PASS (function({a,b}) { return a+b;})(anArray) is '34'
PASS (function ({a:a,b:b}) { return a+b;})(anArray) is '34'
+PASS ({a,b}=anArray); var r=a+b; r is '34'
PASS var {a:a,b:b}=anArray; var r=a+b; r is '34'
Function as String: (function({a:a,b:b}) { return a+b;})
PASS (function({a:a,b:b}) { return a+b;})(anArray) is '34'
PASS (function ({a:a,b:b}) { return a+b;})(anArray) is '34'
+PASS ({a:a,b:b}=anArray); var r=a+b; r is '34'
PASS var {a,b}=anObject; var r=a+b; r is '12'
Function as String: (function({a,b}) { return a+b;})
PASS (function({a,b}) { return a+b;})(anObject) is '12'
PASS (function ({a:a,b:b}) { return a+b;})(anObject) is '12'
+PASS ({a,b}=anObject); var r=a+b; r is '12'
PASS var {a:a,b:b}=anObject; var r=a+b; r is '12'
Function as String: (function({a:a,b:b}) { return a+b;})
PASS (function({a:a,b:b}) { return a+b;})(anObject) is '12'
PASS (function ({a:a,b:b}) { return a+b;})(anObject) is '12'
+PASS ({a:a,b:b}=anObject); var r=a+b; r is '12'
PASS var {0:a,1:b}=anObject; var r=a+b; r is '34'
Function as String: (function({0:a,1:b}) { return a+b;})
PASS (function({0:a,1:b}) { return a+b;})(anObject) is '34'
PASS (function ({0:a,1:b}) { return a+b;})(anObject) is '34'
+PASS ({0:a,1:b}=anObject); var r=a+b; r is '34'
PASS var {'a':a,'b':b}=anObject; var r=a+b; r is '12'
Function as String: (function({'a':a,'b':b}) { return a+b;})
PASS (function({'a':a,'b':b}) { return a+b;})(anObject) is '12'
PASS (function ({"a":a,"b":b}) { return a+b;})(anObject) is '12'
+PASS ({'a':a,'b':b}=anObject); var r=a+b; r is '12'
PASS a+b is '1122'
PASS a+b is '2211'
PASS testDeconstructArgs('1', '2') is '12'
Modified: trunk/LayoutTests/js/parser-syntax-check-expected.txt (159138 => 159139)
--- trunk/LayoutTests/js/parser-syntax-check-expected.txt 2013-11-12 20:50:45 UTC (rev 159138)
+++ trunk/LayoutTests/js/parser-syntax-check-expected.txt 2013-11-12 20:55:29 UTC (rev 159139)
@@ -615,6 +615,10 @@
PASS Valid: "function f() { for (var [of] in of){} }"
PASS Valid: "for (var {of} in of){}"
PASS Valid: "function f() { for (var {of} in of){} }"
+PASS Valid: "for ([of] in of){}"
+PASS Valid: "function f() { for ([of] in of){} }"
+PASS Valid: "for ({of} in of){}"
+PASS Valid: "function f() { for ({of} in of){} }"
PASS Invalid: "for (of of of of){}"
PASS Invalid: "function f() { for (of of of of){} }"
PASS Invalid: "for (of of; of; of){}"
@@ -678,8 +682,16 @@
PASS Valid: "function f() { [...bar,,,,] }"
PASS Valid: "[,,,,...bar]"
PASS Valid: "function f() { [,,,,...bar] }"
-PASS Valid: "({x: 1})"
-PASS Valid: "function f() { ({x: 1}) }"
+PASS Valid: "({1: x})"
+PASS Valid: "function f() { ({1: x}) }"
+PASS Valid: "({1: x}=1)"
+PASS Valid: "function f() { ({1: x}=1) }"
+PASS Valid: "var {1:x}=1"
+PASS Valid: "function f() { var {1:x}=1 }"
+PASS Valid: "[x]=1"
+PASS Valid: "function f() { [x]=1 }"
+PASS Valid: "var [x]=1"
+PASS Valid: "function f() { var [x]=1 }"
PASS Valid: "({[x]: 1})"
PASS Valid: "function f() { ({[x]: 1}) }"
PASS Invalid: "({get [x](){}})"
Modified: trunk/LayoutTests/js/script-tests/basic-for-of.js (159138 => 159139)
--- trunk/LayoutTests/js/script-tests/basic-for-of.js 2013-11-12 20:50:45 UTC (rev 159138)
+++ trunk/LayoutTests/js/script-tests/basic-for-of.js 2013-11-12 20:55:29 UTC (rev 159139)
@@ -54,3 +54,21 @@
testArray[4] = 5
}
shouldBe("testArray.length", String(i))
+
+
+var i = 0;
+for ([key, value] of testArray.entries()) {
+ shouldBe("value", "testArray[key]")
+ shouldBe("key", "i")
+ i++
+ if (i % 2 == 0)
+ testArray[i] *= 2;
+ if (i < 4)
+ testArray.push(testArray.length)
+ if (i == 4)
+ delete testArray[4]
+ if (i == 5)
+ testArray[4] = 5
+}
+shouldBe("testArray.length", String(i))
+
Modified: trunk/LayoutTests/js/script-tests/destructuring-assignment.js (159138 => 159139)
--- trunk/LayoutTests/js/script-tests/destructuring-assignment.js 2013-11-12 20:50:45 UTC (rev 159138)
+++ trunk/LayoutTests/js/script-tests/destructuring-assignment.js 2013-11-12 20:55:29 UTC (rev 159139)
@@ -7,6 +7,9 @@
debug("Function as String: " + functionString);
shouldBe(functionString + "(" + _expression_ + ")", result);
shouldBe("(" + eval(functionString) + ")(" + _expression_ + ")", result);
+ shouldBe("(" + pattern + "=" + _expression_ + "); var r="+expr+"; r", result);
+ if (pattern[0] == '[')
+ shouldBe("" + pattern + "=" + _expression_ + "; var r="+expr+"; r", result);
}
testDestructuring("[a,b]", "['1','2']", "'12'");
Modified: trunk/LayoutTests/js/script-tests/parser-syntax-check.js (159138 => 159139)
--- trunk/LayoutTests/js/script-tests/parser-syntax-check.js 2013-11-12 20:50:45 UTC (rev 159138)
+++ trunk/LayoutTests/js/script-tests/parser-syntax-check.js 2013-11-12 20:55:29 UTC (rev 159139)
@@ -387,6 +387,8 @@
invalid("for (var of[of] in of){}")
valid("for (var [of] in of){}")
valid("for (var {of} in of){}")
+valid("for ([of] in of){}")
+valid("for ({of} in of){}")
invalid("for (of of of of){}")
@@ -422,7 +424,11 @@
valid("[...bar, a]")
valid("[...bar,,,,]")
valid("[,,,,...bar]")
-valid("({x: 1})")
+valid("({1: x})")
+valid("({1: x}=1)")
+valid("var {1:x}=1")
+valid("[x]=1")
+valid("var [x]=1")
valid("({[x]: 1})")
invalid("({get [x](){}})")
invalid("({set [x](){}})")
Modified: trunk/Source/_javascript_Core/ChangeLog (159138 => 159139)
--- trunk/Source/_javascript_Core/ChangeLog 2013-11-12 20:50:45 UTC (rev 159138)
+++ trunk/Source/_javascript_Core/ChangeLog 2013-11-12 20:55:29 UTC (rev 159139)
@@ -1,3 +1,33 @@
+2013-11-11 Oliver Hunt <[email protected]>
+
+ Support unprefixed deconstructing assignment
+ https://bugs.webkit.org/show_bug.cgi?id=124172
+
+ Reviewed by Mark Lam.
+
+ Add support for unprefixed descontructive assignment.
+
+ Happily non-reference types on the left hand side of an assignment
+ are a runtime error, so we're able to defer validation of the binding
+ pattern to codegen time when we're already doing a lot more work.
+
+ We're also able to predicate our attempt to parse on the existence of
+ '[' or '{' as they are not as common as other constructs.
+
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::ArrayPatternNode::emitDirectBinding):
+ * parser/ASTBuilder.h:
+ * parser/Parser.cpp:
+ (JSC::::createBindingPattern):
+ (JSC::::tryParseDeconstructionPatternExpression):
+ (JSC::::parseDeconstructionPattern):
+ (JSC::::parseForStatement):
+ (JSC::::parseAssignmentExpression):
+ * parser/Parser.h:
+ (JSC::Parser::createSavePoint):
+ (JSC::Parser::restoreSavePoint):
+ * parser/SyntaxChecker.h:
+
2013-11-12 Andy Estes <[email protected]>
Run _javascript_Core Objective-C API tests on all supported platforms
Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (159138 => 159139)
--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2013-11-12 20:50:45 UTC (rev 159138)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2013-11-12 20:55:29 UTC (rev 159139)
@@ -2333,11 +2333,17 @@
generator.emitGetArgumentByVal(temp.get(), generator.uncheckedRegisterForArguments(), temp.get());
target->bindValue(generator, temp.get());
}
- return generator.emitLoad(generator.finalDestination(dst), jsUndefined());
+ if (dst == generator.ignoredResult() || !dst)
+ return generator.emitLoad(generator.finalDestination(dst), jsUndefined());
+ Local local = generator.local(generator.vm()->propertyNames->arguments);
+ return generator.moveToDestinationIfNeeded(dst, local.get());
}
if (!rhs->isSimpleArray())
return 0;
+ RefPtr<RegisterID> resultRegister;
+ if (dst && dst != generator.ignoredResult())
+ resultRegister = generator.emitNewArray(generator.newTemporary(), 0, 0);
ElementNode* elementNodes = static_cast<ArrayNode*>(rhs)->elements();
Vector<ExpressionNode*> elements;
for (; elementNodes; elementNodes = elementNodes->next())
@@ -2349,13 +2355,16 @@
for (size_t i = 0; i < m_targetPatterns.size(); i++) {
registers.uncheckedAppend(generator.newTemporary());
generator.emitNode(registers.last().get(), elements[i]);
+ if (resultRegister)
+ generator.emitPutByIndex(resultRegister.get(), i, registers.last().get());
}
for (size_t i = 0; i < m_targetPatterns.size(); i++) {
if (m_targetPatterns[i])
m_targetPatterns[i]->bindValue(generator, registers[i].get());
}
-
+ if (resultRegister)
+ return generator.moveToDestinationIfNeeded(dst, resultRegister.get());
return generator.emitLoad(generator.finalDestination(dst), jsUndefined());
}
Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (159138 => 159139)
--- trunk/Source/_javascript_Core/parser/Parser.cpp 2013-11-12 20:50:45 UTC (rev 159138)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp 2013-11-12 20:55:29 UTC (rev 159139)
@@ -400,7 +400,8 @@
semanticFail("Cannot deconstruct to a parameter named '", name.impl(), "'");
}
}
- context.addVar(&name, kind == DeconstructToParameters ? 0 : DeclarationStacks::HasInitializer);
+ if (kind != DeconstructToExpressions)
+ context.addVar(&name, kind == DeconstructToParameters ? 0 : DeclarationStacks::HasInitializer);
} else {
if (kind == DeconstructToVariables) {
failIfFalseIfStrict(declareVariable(&name), "Cannot declare a variable named '", name.impl(), "' in strict mode");
@@ -424,6 +425,12 @@
}
template <typename LexerType>
+template <class TreeBuilder> TreeDeconstructionPattern Parser<LexerType>::tryParseDeconstructionPatternExpression(TreeBuilder& context)
+{
+ return parseDeconstructionPattern<DeconstructToExpressions>(context);
+}
+
+template <typename LexerType>
template <DeconstructionKind kind, class TreeBuilder> TreeDeconstructionPattern Parser<LexerType>::parseDeconstructionPattern(TreeBuilder& context, int depth)
{
failIfStackOverflow();
@@ -433,6 +440,8 @@
case OPENBRACKET: {
auto arrayPattern = context.createArrayPattern(m_token.m_location);
next();
+ if (kind == DeconstructToExpressions && match(CLOSEBRACKET))
+ return 0;
failIfTrue(match(CLOSEBRACKET), "There must be at least one bound property in an array deconstruction pattern");
do {
while (match(COMMA)) {
@@ -442,15 +451,25 @@
propagateError();
JSTokenLocation location = m_token.m_location;
auto innerPattern = parseDeconstructionPattern<kind>(context, depth + 1);
+ if (kind == DeconstructToExpressions && !innerPattern)
+ return 0;
failIfFalse(innerPattern, "Cannot parse this deconstruction pattern");
context.appendArrayPatternEntry(arrayPattern, location, innerPattern);
} while (consume(COMMA));
+
+ if (kind == DeconstructToExpressions && !match(CLOSEBRACKET))
+ return 0;
+
consumeOrFail(CLOSEBRACKET, "Expected either a closing ']' or a ',' following an element deconstruction pattern");
pattern = arrayPattern;
break;
}
case OPENBRACE: {
next();
+
+ if (kind == DeconstructToExpressions && match(CLOSEBRACE))
+ return 0;
+
failIfTrue(match(CLOSEBRACE), "There must be at least one bound property in an object deconstruction pattern");
auto objectPattern = context.createObjectPattern(m_token.m_location);
bool wasString = false;
@@ -476,13 +495,18 @@
wasString = true;
break;
default:
- if (m_token.m_type != RESERVED && m_token.m_type != RESERVED_IF_STRICT && !(m_token.m_type & KeywordTokenFlag))
+ if (m_token.m_type != RESERVED && m_token.m_type != RESERVED_IF_STRICT && !(m_token.m_type & KeywordTokenFlag)) {
+ if (kind == DeconstructToExpressions)
+ return 0;
failWithMessage("Expected a property name");
+ }
propertyName = *m_token.m_data.ident;
break;
}
next();
if (!consume(COLON)) {
+ if (kind == DeconstructToExpressions)
+ return 0;
semanticFailIfTrue(tokenType == RESERVED, "Cannot use abbreviated deconstruction syntax for reserved name '", propertyName.impl(), "'");
semanticFailIfTrue(tokenType == RESERVED_IF_STRICT, "Cannot use abbreviated deconstruction syntax for reserved name '", propertyName.impl(), "' in strict mode");
semanticFailIfTrue(tokenType & KeywordTokenFlag, "Cannot use abbreviated deconstruction syntax for keyword '", propertyName.impl(), "'");
@@ -491,9 +515,13 @@
}
innerPattern = parseDeconstructionPattern<kind>(context, depth + 1);
}
+ if (kind == DeconstructToExpressions && !innerPattern)
+ return 0;
failIfFalse(innerPattern, "Cannot parse this deconstruction pattern");
context.appendObjectPatternEntry(objectPattern, location, wasString, propertyName, innerPattern);
} while (consume(COMMA));
+ if (kind == DeconstructToExpressions && !match(CLOSEBRACE))
+ return 0;
consumeOrFail(CLOSEBRACE, "Expected either a closing '}' or an ',' after a property deconstruction pattern");
pattern = objectPattern;
break;
@@ -501,6 +529,8 @@
default: {
if (!match(IDENT)) {
+ if (kind == DeconstructToExpressions)
+ return 0;
semanticFailureDueToKeyword("variable name");
failWithMessage("Expected a parameter pattern or a ')' in parameter list");
}
@@ -554,6 +584,7 @@
JSTextPosition declsStart;
JSTextPosition declsEnd;
TreeExpression decls = 0;
+ TreeDeconstructionPattern pattern = 0;
if (match(VAR)) {
/*
for (var IDENT in _expression_) statement
@@ -603,6 +634,16 @@
}
if (!match(SEMICOLON)) {
+ if (match(OPENBRACE) || match(OPENBRACKET)) {
+ SavePoint savePoint = createSavePoint();
+ declsStart = tokenStartPosition();
+ pattern = tryParseDeconstructionPatternExpression(context);
+ declsEnd = lastTokenEndPosition();
+ if (pattern && (match(INTOKEN) || (match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of)))
+ goto enumerationLoop;
+ pattern = 0;
+ restoreSavePoint(savePoint);
+ }
m_allowsIn = false;
declsStart = tokenStartPosition();
decls = parseExpression(context);
@@ -639,6 +680,7 @@
}
// For-in loop
+enumerationLoop:
failIfFalse(nonLHSCount == m_nonLHSCount, "Expected a reference on the left hand side of an enumeration statement");
bool isOfEnumeration = false;
if (!consume(INTOKEN)) {
@@ -657,6 +699,12 @@
TreeStatement statement = parseStatement(context, unused);
endLoop();
failIfFalse(statement, "Expected a statement as the body of a for-", isOfEnumeration ? "of" : "in", "loop");
+ if (pattern) {
+ ASSERT(!decls);
+ if (isOfEnumeration)
+ return context.createForOfLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
+ return context.createForInLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
+ }
if (isOfEnumeration)
return context.createForOfLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
return context.createForInLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
@@ -1368,6 +1416,16 @@
JSTokenLocation location(tokenLocation());
int initialAssignmentCount = m_assignmentCount;
int initialNonLHSCount = m_nonLHSCount;
+ if (match(OPENBRACE) || match(OPENBRACKET)) {
+ SavePoint savePoint = createSavePoint();
+ auto pattern = tryParseDeconstructionPatternExpression(context);
+ if (pattern && consume(EQUAL)) {
+ auto rhs = parseAssignmentExpression(context);
+ if (rhs)
+ return context.createDeconstructingAssignment(location, pattern, rhs);
+ }
+ restoreSavePoint(savePoint);
+ }
TreeExpression lhs = parseConditionalExpression(context);
failIfFalse(lhs, "Cannot parse _expression_");
if (initialNonLHSCount != m_nonLHSCount) {
Modified: trunk/Source/_javascript_Core/parser/Parser.h (159138 => 159139)
--- trunk/Source/_javascript_Core/parser/Parser.h 2013-11-12 20:50:45 UTC (rev 159138)
+++ trunk/Source/_javascript_Core/parser/Parser.h 2013-11-12 20:55:29 UTC (rev 159139)
@@ -731,6 +731,7 @@
template <DeconstructionKind, class TreeBuilder> ALWAYS_INLINE TreeDeconstructionPattern createBindingPattern(TreeBuilder&, const Identifier&, int depth);
template <DeconstructionKind, class TreeBuilder> TreeDeconstructionPattern parseDeconstructionPattern(TreeBuilder&, int depth = 0);
+ template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern tryParseDeconstructionPatternExpression(TreeBuilder&);
template <FunctionRequirements, FunctionParseMode, bool nameIsInContainingScope, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, unsigned& openBraceOffset, unsigned& closeBraceOffset, int& bodyStartLine, unsigned& bodyStartColumn);
ALWAYS_INLINE int isBinaryOperator(JSTokenType);
bool allowAutomaticSemicolon();
@@ -768,6 +769,7 @@
ALWAYS_INLINE SavePoint createSavePoint()
{
+ ASSERT(!hasError());
SavePoint result;
result.startOffset = m_token.m_location.startOffset;
result.oldLineStartOffset = m_token.m_location.lineStartOffset;
@@ -778,6 +780,7 @@
ALWAYS_INLINE void restoreSavePoint(const SavePoint& savePoint)
{
+ m_errorMessage = String();
m_lexer->setOffset(savePoint.startOffset, savePoint.oldLineStartOffset);
next();
m_lexer->setLastLineNumber(savePoint.oldLastLineNumber);