Diff
Modified: trunk/LayoutTests/ChangeLog (185698 => 185699)
--- trunk/LayoutTests/ChangeLog 2015-06-18 09:22:48 UTC (rev 185698)
+++ trunk/LayoutTests/ChangeLog 2015-06-18 12:35:32 UTC (rev 185699)
@@ -1,3 +1,25 @@
+2015-06-18 Saam Barati <saambara...@gmail.com>
+
+ [ES6] support default values in deconstruction parameter nodes
+ https://bugs.webkit.org/show_bug.cgi?id=142679
+
+ Reviewed by Darin Adler.
+
+ * js/destructuring-assignment-default-values-expected.txt: Added.
+ * js/destructuring-assignment-default-values.html: Added.
+ * js/script-tests/destructuring-assignment-default-values.js: Added.
+ (assert):
+ (test1):
+ (arr):
+ (test2):
+ (test3):
+ (test4):
+ (test5):
+ (test6):
+ (test7):
+ (test8):
+ (shouldThrow):
+
2015-06-18 Youenn Fablet <youenn.fab...@crf.canon.fr> and Xabier Rodriguez Calvar <calva...@igalia.com>
[Streams API] Implement ReadableStreamReader.releaseLock
Added: trunk/LayoutTests/js/destructuring-assignment-default-values-expected.txt (0 => 185699)
--- trunk/LayoutTests/js/destructuring-assignment-default-values-expected.txt (rev 0)
+++ trunk/LayoutTests/js/destructuring-assignment-default-values-expected.txt 2015-06-18 12:35:32 UTC (rev 185699)
@@ -0,0 +1,44 @@
+Test default values in destructuring patterns: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-destructuring-binding-patterns
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS 40,40
+PASS 40,40
+PASS 100,100
+PASS Hello,Hello
+PASS 20,20
+PASS 30,30
+PASS Hello,Hello
+PASS 20,20
+PASS 30,30
+PASS z,z
+PASS zz,zz
+PASS 40,40
+PASS 50,50
+PASS 40,40
+PASS 50,50
+PASS 100,100
+PASS null,null
+PASS false,false
+PASS 0,0
+PASS 50,50
+PASS 51,51
+PASS 51,51
+PASS 52,52
+PASS undefined,undefined
+PASS undefined,undefined
+PASS 10,10
+PASS 30,30
+PASS 120,120
+PASS 3628800,3628800
+PASS 1,1
+PASS true,true
+PASS true,true
+PASS true,true
+PASS true,true
+PASS true,true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/js/destructuring-assignment-default-values.html (0 => 185699)
--- trunk/LayoutTests/js/destructuring-assignment-default-values.html (rev 0)
+++ trunk/LayoutTests/js/destructuring-assignment-default-values.html 2015-06-18 12:35:32 UTC (rev 185699)
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/js/script-tests/destructuring-assignment-default-values.js (0 => 185699)
--- trunk/LayoutTests/js/script-tests/destructuring-assignment-default-values.js (rev 0)
+++ trunk/LayoutTests/js/script-tests/destructuring-assignment-default-values.js 2015-06-18 12:35:32 UTC (rev 185699)
@@ -0,0 +1,125 @@
+description("Test default values in destructuring patterns: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-destructuring-binding-patterns");
+function assert(a, b) {
+ if (b === a)
+ testPassed(a + "," + b);
+ else
+ testFailed(a + "," + b);
+}
+
+function test1() {
+ var {x = 40} = {};
+ var {prop: y = 40} = {};
+ var {prop: {z} = {z: 100}} = {};
+ assert(x, 40);
+ assert(y, 40);
+ assert(z, 100);
+}
+test1();
+
+function arr() { return [undefined, 20, undefined]; }
+
+function test2() {
+ var [x = "Hello", y = 40, z = 30] = [undefined, 20, undefined];
+ assert(x, "Hello");
+ assert(y, 20);
+ assert(z, 30);
+ var [x = "Hello", y = 40, z = 30] = arr();
+ assert(x, "Hello");
+ assert(y, 20);
+ assert(z, 30);
+}
+test2();
+
+
+function test3() {
+ var z = "z";
+ var [x = z] = [];
+ assert(x, "z");
+ z = "zz";
+ var [x = eval("z")] = [];
+ assert(x, "zz");
+
+ var [{a} = {a: 40}] = [undefined];
+ assert(a, 40);
+ var [{a = 50}] = [{a: undefined}];
+ assert(a, 50);
+}
+test3();
+
+
+function test4() {
+ var [{prop: {b = 40}}] = [{prop: {b: undefined}}];
+ var [{prop: [c = 50]}] = [{prop: []}];
+ var [{prop: [d = 60]} = {prop: [100]}] = [];
+ assert(b, 40);
+ assert(c, 50);
+ assert(d, 100)
+}
+test4();
+
+
+function test5() {
+ var {x = undefined} = {x: null};
+ assert(x, null);
+ var {x = undefined} = {x: false};
+ assert(x, false);
+ var {x = undefined} = {x: 0};
+ assert(x, 0);
+}
+test5();
+
+
+function test6() {
+ var [x = 50, y = x + 1] = [];
+ assert(x, 50);
+ assert(y, 51);
+
+ var [x = y, y = x + 1] = [];
+ assert(x, 51);
+ assert(y, 52);
+
+ // FIXME: make tests for TDZ failures when we land block scoping 'let' and 'const'.
+ var [a = b, b = a] = [];
+ assert(a, undefined);
+ assert(b, undefined);
+}
+test6();
+
+
+function test7(a, b) {
+ var {c = a, d = c + b} = {};
+ assert(c, 10);
+ assert(d, 30);
+}
+test7(10, 20);
+
+
+function test8(x) {
+ // How much uglier can we make a factorial function?
+ if (x <= 0)
+ return {p: 1};
+
+ var {p = {p: x * test8(x - 1).p}} = {};
+ return p;
+}
+assert(test8(5).p, 120);
+assert(test8(10).p, 3628800);
+assert(test8(0).p, 1);
+
+// FIXME: When we support default values in function parameters, we should remove this test.
+function shouldThrow(str) {
+ var thrown = false;
+ try {
+ eval(str);
+ } catch(e) {
+ thrown = true;
+ }
+
+ assert(true, thrown);
+}
+
+shouldThrow("(function({x = 40}) {})");
+shouldThrow("(function({y}, {x = 40}) {}");
+shouldThrow("(function([y], [x = 40]) {})");
+shouldThrow("(function({y}, {x: {z = 50}}) {})");
+shouldThrow("(function({y}, {x: [z = 50]}) {})");
Modified: trunk/Source/_javascript_Core/ChangeLog (185698 => 185699)
--- trunk/Source/_javascript_Core/ChangeLog 2015-06-18 09:22:48 UTC (rev 185698)
+++ trunk/Source/_javascript_Core/ChangeLog 2015-06-18 12:35:32 UTC (rev 185699)
@@ -1,3 +1,48 @@
+2015-06-18 Saam Barati <saambara...@gmail.com>
+
+ [ES6] support default values in deconstruction parameter nodes
+ https://bugs.webkit.org/show_bug.cgi?id=142679
+
+ Reviewed by Darin Adler.
+
+ ES6 destructuring allows destructuring properties to assign
+ default values. A link to the spec:
+ https://people.mozilla.org/~jorendorff/es6-draft.html#sec-destructuring-binding-patterns
+
+ This patch implements default values for all places where deconstruction
+ is allowed besides function parameters. This is because function
+ parameters are parsed in a separate parser arena than the function
+ body itself and ExpresionNode's which are default values for
+ deconstruction parameters will be deallocated by the time we parse the body
+ of the function. I have opened a bug to address this problem:
+ https://bugs.webkit.org/show_bug.cgi?id=145995
+
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::DeconstructionPatternNode::~DeconstructionPatternNode):
+ (JSC::assignDefaultValueIfUndefined):
+ (JSC::ArrayPatternNode::bindValue):
+ (JSC::ArrayPatternNode::emitDirectBinding):
+ (JSC::ArrayPatternNode::toString):
+ (JSC::ArrayPatternNode::collectBoundIdentifiers):
+ (JSC::ObjectPatternNode::bindValue):
+ * parser/ASTBuilder.h:
+ (JSC::ASTBuilder::appendArrayPatternSkipEntry):
+ (JSC::ASTBuilder::appendArrayPatternEntry):
+ (JSC::ASTBuilder::createObjectPattern):
+ (JSC::ASTBuilder::appendObjectPatternEntry):
+ (JSC::ASTBuilder::createBindingLocation):
+ * parser/Nodes.h:
+ (JSC::ArrayPatternNode::appendIndex):
+ (JSC::ObjectPatternNode::appendEntry):
+ (JSC::ObjectPatternNode::Entry::Entry): Deleted.
+ * parser/Parser.cpp:
+ (JSC::Parser<LexerType>::parseDeconstructionPattern):
+ (JSC::Parser<LexerType>::parseDefaultValueForDeconstructionPattern):
+ (JSC::Parser<LexerType>::parseConstDeclarationList):
+ * parser/Parser.h:
+ * parser/SyntaxChecker.h:
+ (JSC::SyntaxChecker::operatorStackPop):
+
2015-06-17 Joseph Pecoraro <pecor...@apple.com>
Web Inspector: Do not show _javascript_Core builtins in inspector
Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (185698 => 185699)
--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2015-06-18 09:22:48 UTC (rev 185698)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2015-06-18 12:35:32 UTC (rev 185699)
@@ -3119,17 +3119,28 @@
DeconstructionPatternNode::~DeconstructionPatternNode()
{
}
+
+static void assignDefaultValueIfUndefined(BytecodeGenerator& generator, RegisterID* maybeUndefined, ExpressionNode* defaultValue)
+{
+ ASSERT(defaultValue);
+ RefPtr<Label> isNotUndefined = generator.newLabel();
+ generator.emitJumpIfFalse(generator.emitIsUndefined(generator.newTemporary(), maybeUndefined), isNotUndefined.get());
+ generator.emitNode(maybeUndefined, defaultValue);
+ generator.emitLabel(isNotUndefined.get());
+}
void ArrayPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs) const
{
for (size_t i = 0; i < m_targetPatterns.size(); i++) {
auto target = m_targetPatterns[i];
- if (!target)
+ if (!target.pattern)
continue;
RefPtr<RegisterID> temp = generator.newTemporary();
generator.emitLoad(temp.get(), jsNumber(i));
generator.emitGetByVal(temp.get(), rhs, temp.get());
- target->bindValue(generator, temp.get());
+ if (target.defaultValue)
+ assignDefaultValueIfUndefined(generator, temp.get(), target.defaultValue);
+ target.pattern->bindValue(generator, temp.get());
}
}
@@ -3152,13 +3163,15 @@
for (size_t i = 0; i < m_targetPatterns.size(); i++) {
registers.uncheckedAppend(generator.newTemporary());
generator.emitNode(registers.last().get(), elements[i]);
+ if (m_targetPatterns[i].defaultValue)
+ assignDefaultValueIfUndefined(generator, registers.last().get(), m_targetPatterns[i].defaultValue);
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 (m_targetPatterns[i].pattern)
+ m_targetPatterns[i].pattern->bindValue(generator, registers[i].get());
}
if (resultRegister)
return generator.moveToDestinationIfNeeded(dst, resultRegister.get());
@@ -3169,11 +3182,11 @@
{
builder.append('[');
for (size_t i = 0; i < m_targetPatterns.size(); i++) {
- if (!m_targetPatterns[i]) {
+ if (!m_targetPatterns[i].pattern) {
builder.append(',');
continue;
}
- m_targetPatterns[i]->toString(builder);
+ m_targetPatterns[i].pattern->toString(builder);
if (i < m_targetPatterns.size() - 1)
builder.append(',');
}
@@ -3183,7 +3196,7 @@
void ArrayPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const
{
for (size_t i = 0; i < m_targetPatterns.size(); i++) {
- if (DeconstructionPatternNode* node = m_targetPatterns[i].get())
+ if (DeconstructionPatternNode* node = m_targetPatterns[i].pattern.get())
node->collectBoundIdentifiers(identifiers);
}
}
@@ -3210,6 +3223,8 @@
auto& target = m_targetPatterns[i];
RefPtr<RegisterID> temp = generator.newTemporary();
generator.emitGetById(temp.get(), rhs, target.propertyName);
+ if (target.defaultValue)
+ assignDefaultValueIfUndefined(generator, temp.get(), target.defaultValue);
target.pattern->bindValue(generator, temp.get());
}
}
Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (185698 => 185699)
--- trunk/Source/_javascript_Core/parser/ASTBuilder.h 2015-06-18 09:22:48 UTC (rev 185698)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h 2015-06-18 12:35:32 UTC (rev 185699)
@@ -737,12 +737,12 @@
void appendArrayPatternSkipEntry(ArrayPattern node, const JSTokenLocation& location)
{
- node->appendIndex(location, 0);
+ node->appendIndex(location, 0, nullptr);
}
- void appendArrayPatternEntry(ArrayPattern node, const JSTokenLocation& location, DeconstructionPattern pattern)
+ void appendArrayPatternEntry(ArrayPattern node, const JSTokenLocation& location, DeconstructionPattern pattern, ExpressionNode* defaultValue)
{
- node->appendIndex(location, pattern.get());
+ node->appendIndex(location, pattern.get(), defaultValue);
}
ObjectPattern createObjectPattern(const JSTokenLocation&)
@@ -750,9 +750,9 @@
return ObjectPatternNode::create();
}
- void appendObjectPatternEntry(ObjectPattern node, const JSTokenLocation& location, bool wasString, const Identifier& identifier, DeconstructionPattern pattern)
+ void appendObjectPatternEntry(ObjectPattern node, const JSTokenLocation& location, bool wasString, const Identifier& identifier, DeconstructionPattern pattern, ExpressionNode* defaultValue)
{
- node->appendEntry(location, identifier, wasString, pattern.get());
+ node->appendEntry(location, identifier, wasString, pattern.get(), defaultValue);
}
BindingPattern createBindingLocation(const JSTokenLocation&, const Identifier& boundProperty, const JSTextPosition& start, const JSTextPosition& end)
Modified: trunk/Source/_javascript_Core/parser/Nodes.h (185698 => 185699)
--- trunk/Source/_javascript_Core/parser/Nodes.h 2015-06-18 09:22:48 UTC (rev 185698)
+++ trunk/Source/_javascript_Core/parser/Nodes.h 2015-06-18 12:35:32 UTC (rev 185699)
@@ -1783,27 +1783,31 @@
class ArrayPatternNode : public DeconstructionPatternNode {
public:
static Ref<ArrayPatternNode> create();
- void appendIndex(const JSTokenLocation&, DeconstructionPatternNode* node)
+ void appendIndex(const JSTokenLocation&, DeconstructionPatternNode* node, ExpressionNode* defaultValue)
{
- m_targetPatterns.append(node);
+ m_targetPatterns.append(Entry{ node, defaultValue });
}
private:
+ struct Entry {
+ RefPtr<DeconstructionPatternNode> pattern;
+ ExpressionNode* defaultValue;
+ };
ArrayPatternNode();
virtual void collectBoundIdentifiers(Vector<Identifier>&) const override;
virtual void bindValue(BytecodeGenerator&, RegisterID*) const override;
virtual RegisterID* emitDirectBinding(BytecodeGenerator&, RegisterID* dst, ExpressionNode*) override;
virtual void toString(StringBuilder&) const override;
- Vector<RefPtr<DeconstructionPatternNode>> m_targetPatterns;
+ Vector<Entry> m_targetPatterns;
};
class ObjectPatternNode : public DeconstructionPatternNode {
public:
static Ref<ObjectPatternNode> create();
- void appendEntry(const JSTokenLocation&, const Identifier& identifier, bool wasString, DeconstructionPatternNode* pattern)
+ void appendEntry(const JSTokenLocation&, const Identifier& identifier, bool wasString, DeconstructionPatternNode* pattern, ExpressionNode* defaultValue)
{
- m_targetPatterns.append(Entry(identifier, wasString, pattern));
+ m_targetPatterns.append(Entry{ identifier, wasString, pattern, defaultValue });
}
private:
@@ -1812,15 +1816,10 @@
virtual void bindValue(BytecodeGenerator&, RegisterID*) const override;
virtual void toString(StringBuilder&) const override;
struct Entry {
- Entry(const Identifier& propertyName, bool wasString, DeconstructionPatternNode* pattern)
- : propertyName(propertyName)
- , wasString(wasString)
- , pattern(pattern)
- {
- }
Identifier propertyName;
bool wasString;
RefPtr<DeconstructionPatternNode> pattern;
+ ExpressionNode* defaultValue;
};
Vector<Entry> m_targetPatterns;
};
Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (185698 => 185699)
--- trunk/Source/_javascript_Core/parser/Parser.cpp 2015-06-18 09:22:48 UTC (rev 185698)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp 2015-06-18 12:35:32 UTC (rev 185699)
@@ -613,7 +613,9 @@
if (kind == DeconstructToExpressions && !innerPattern)
return 0;
failIfFalse(innerPattern, "Cannot parse this deconstruction pattern");
- context.appendArrayPatternEntry(arrayPattern, location, innerPattern);
+ TreeExpression defaultValue = parseDefaultValueForDeconstructionPattern(context);
+ failIfTrue(kind == DeconstructToParameters && defaultValue, "Default values in destructuring parameters are currently not supported");
+ context.appendArrayPatternEntry(arrayPattern, location, innerPattern, defaultValue);
} while (consume(COMMA));
if (kind == DeconstructToExpressions && !match(CLOSEBRACKET))
@@ -679,7 +681,9 @@
if (kind == DeconstructToExpressions && !innerPattern)
return 0;
failIfFalse(innerPattern, "Cannot parse this deconstruction pattern");
- context.appendObjectPatternEntry(objectPattern, location, wasString, propertyName, innerPattern);
+ TreeExpression defaultValue = parseDefaultValueForDeconstructionPattern(context);
+ failIfTrue(kind == DeconstructToParameters && defaultValue, "Default values in destructuring parameters are currently not supported");
+ context.appendObjectPatternEntry(objectPattern, location, wasString, propertyName, innerPattern, defaultValue);
} while (consume(COMMA));
if (kind == DeconstructToExpressions && !match(CLOSEBRACE))
return 0;
@@ -705,6 +709,16 @@
}
template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseDefaultValueForDeconstructionPattern(TreeBuilder& context)
+{
+ if (!match(EQUAL))
+ return 0;
+
+ next(TreeBuilder::DontBuildStrings); // consume '='
+ return parseAssignmentExpression(context);
+}
+
+template <typename LexerType>
template <class TreeBuilder> TreeConstDeclList Parser<LexerType>::parseConstDeclarationList(TreeBuilder& context)
{
failIfTrue(strictMode(), "Const declarations are not supported in strict mode");
Modified: trunk/Source/_javascript_Core/parser/Parser.h (185698 => 185699)
--- trunk/Source/_javascript_Core/parser/Parser.h 2015-06-18 09:22:48 UTC (rev 185698)
+++ trunk/Source/_javascript_Core/parser/Parser.h 2015-06-18 12:35:32 UTC (rev 185699)
@@ -765,6 +765,7 @@
template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern createBindingPattern(TreeBuilder&, DeconstructionKind, const Identifier&, int depth, JSToken);
template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern parseDeconstructionPattern(TreeBuilder&, DeconstructionKind, int depth = 0);
template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern tryParseDeconstructionPatternExpression(TreeBuilder&);
+ template <class TreeBuilder> NEVER_INLINE TreeExpression parseDefaultValueForDeconstructionPattern(TreeBuilder&);
template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionRequirements, FunctionParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&);
Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (185698 => 185699)
--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2015-06-18 09:22:48 UTC (rev 185698)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2015-06-18 12:35:32 UTC (rev 185699)
@@ -308,14 +308,14 @@
void appendArrayPatternSkipEntry(ArrayPattern, const JSTokenLocation&)
{
}
- void appendArrayPatternEntry(ArrayPattern, const JSTokenLocation&, DeconstructionPattern)
+ void appendArrayPatternEntry(ArrayPattern, const JSTokenLocation&, DeconstructionPattern, int)
{
}
ObjectPattern createObjectPattern(const JSTokenLocation&)
{
return ObjectDeconstruction;
}
- void appendObjectPatternEntry(ArrayPattern, const JSTokenLocation&, bool, const Identifier&, DeconstructionPattern)
+ void appendObjectPatternEntry(ArrayPattern, const JSTokenLocation&, bool, const Identifier&, DeconstructionPattern, int)
{
}
DeconstructionPattern createBindingLocation(const JSTokenLocation&, const Identifier&, const JSTextPosition&, const JSTextPosition&)