Commit 20a9bf08 authored by oliver@apple.com's avatar oliver@apple.com

Support for-of syntax

https://bugs.webkit.org/show_bug.cgi?id=122339

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

Add support for for-of syntax to JSC.  As part of doing this I had to make
us support unique empty strings as identifiers.  In a follow on patch i'm
going to remove the distinction entirely as it's purely a complicating
separation.

Otherwise the logic here is fairly self-explanatory.

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::addConstant):
(JSC::BytecodeGenerator::emitCall):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::CallArguments::CallArguments):
(JSC::ForOfNode::emitBytecode):
* jit/JITOperations.cpp:
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createForOfLoop):
* parser/NodeConstructors.h:
(JSC::EnumerationNode::EnumerationNode):
(JSC::ForInNode::ForInNode):
(JSC::ForOfNode::ForOfNode):
* parser/Nodes.h:
* parser/Parser.cpp:
(JSC::::parseVarDeclarationList):
(JSC::::parseForStatement):
* parser/Parser.h:
(JSC::Parser::isofToken):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createForOfLoop):
* runtime/ArrayIteratorPrototype.cpp:
(JSC::ArrayIteratorPrototype::finishCreation):
(JSC::arrayIteratorPrototypeIterate):
* runtime/ArrayPrototype.cpp:
(JSC::ArrayPrototype::create):
(JSC::ArrayPrototype::finishCreation):
* runtime/ArrayPrototype.h:
* runtime/CommonIdentifiers.cpp:
(JSC::CommonIdentifiers::CommonIdentifiers):
* runtime/CommonIdentifiers.h:
* runtime/Identifier.h:
(JSC::Identifier::from):
* runtime/JSCJSValue.cpp:
(JSC::JSValue::dumpInContext):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::reset):
* runtime/JSObject.cpp:
(JSC::JSObject::putDirectNativeFunction):
* runtime/PrivateName.h:
(JSC::PrivateName::PrivateName):
* runtime/PropertyName.h:
(JSC::PropertyName::PropertyName):

Source/WTF:

Update assertions and add a helper function to StringImpl
to save repeated unique or identifier calls.

* wtf/text/StringImpl.h:
(WTF::StringImpl::isIdentifierOrUnique):
(WTF::StringImpl::setIsIdentifier):
(WTF::StringImpl::setIsAtomic):

LayoutTests:

Add test cases for the one type that supports for-of so far

* js/basic-for-of-expected.txt: Added.
* js/basic-for-of.html: Added.
* js/regress/for-of-iterate-array-entries.html: Added.
* js/regress/for-of-iterate-array-keys.html: Added.
* js/regress/for-of-iterate-array-values.html: Added.
* js/regress/script-tests/for-of-iterate-array-entries.js: Added.
(foo):
* js/regress/script-tests/for-of-iterate-array-keys.js: Added.
(foo):
* js/regress/script-tests/for-of-iterate-array-values.js: Added.
(foo):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@156910 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent b684bfaf
2013-10-04 Oliver Hunt <oliver@apple.com>
Support for-of syntax
https://bugs.webkit.org/show_bug.cgi?id=122339
Reviewed by Geoffrey Garen.
Add test cases for the one type that supports for-of so far
* js/basic-for-of-expected.txt: Added.
* js/basic-for-of.html: Added.
* js/regress/for-of-iterate-array-entries.html: Added.
* js/regress/for-of-iterate-array-keys.html: Added.
* js/regress/for-of-iterate-array-values.html: Added.
* js/regress/script-tests/for-of-iterate-array-entries.js: Added.
(foo):
* js/regress/script-tests/for-of-iterate-array-keys.js: Added.
(foo):
* js/regress/script-tests/for-of-iterate-array-values.js: Added.
(foo):
2013-10-04 Bear Travis <betravis@adobe.com>
[CSS Shapes] Shape Outside should relayout when set dynamically
This test checks the behavior of the for-of construct.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS value is testArray[0]
PASS value is testArray[1]
PASS value is testArray[2]
PASS value is testArray[3]
PASS value is testArray[4]
PASS value is testArray[5]
PASS testArray.length is 6
PASS value is testArray[0]
PASS value is testArray[1]
PASS value is testArray[2]
PASS value is testArray[3]
PASS value is testArray[4]
PASS value is testArray[5]
PASS testArray.length is 6
PASS key is 0
PASS key is 1
PASS key is 2
PASS key is 3
PASS key is 4
PASS key is 5
PASS testArray.length is 6
PASS this.prop1 is 0
PASS this.prop1 is 1
PASS this.prop1 is 2
PASS this.prop1 is 3
PASS this.prop1 is 4
PASS this.prop1 is 5
PASS testArray.length is 6
PASS this[prop2] is 0
PASS this[prop2] is 1
PASS this[prop2] is 2
PASS this[prop2] is 3
PASS this[prop2] is 4
PASS this[prop2] is 5
PASS testArray.length is 6
PASS key is 0
PASS value is 1
PASS key is 1
PASS value is 2
PASS key is 2
PASS value is 3
PASS key is 3
PASS value is 4
PASS key is 4
PASS value is 5
PASS key is 5
PASS value is 6
PASS testArray.length is 6
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 9
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../resources/js-test-pre.js"></script>
</head>
<body>
<script src="script-tests/basic-for-of.js"></script>
<script src="../resources/js-test-post.js"></script>
</body>
</html>
......@@ -579,6 +579,58 @@ PASS Invalid: "var a.b = c"
PASS Invalid: "function f() { var a.b = c }"
PASS Invalid: "var a.b;"
PASS Invalid: "function f() { var a.b; }"
PASS Valid: "for (of of of){}"
PASS Valid: "function f() { for (of of of){} }"
PASS Valid: "for (of; of; of){}"
PASS Valid: "function f() { for (of; of; of){} }"
PASS Valid: "for (var of of of){}"
PASS Valid: "function f() { for (var of of of){} }"
PASS Valid: "for (var of; of; of){}"
PASS Valid: "function f() { for (var of; of; of){} }"
PASS Invalid: "for (var of.of of of){}"
PASS Invalid: "function f() { for (var of.of of of){} }"
PASS Invalid: "for (var of[of] of of){}"
PASS Invalid: "function f() { for (var of[of] of of){} }"
PASS Valid: "for (of.of of of){}"
PASS Valid: "function f() { for (of.of of of){} }"
PASS Valid: "for (of[of] of of){}"
PASS Valid: "function f() { for (of[of] of of){} }"
PASS Valid: "for (var [of] of of){}"
PASS Valid: "function f() { for (var [of] of of){} }"
PASS Valid: "for (var {of} of of){}"
PASS Valid: "function f() { for (var {of} of of){} }"
PASS Valid: "for (of in of){}"
PASS Valid: "function f() { for (of in of){} }"
PASS Valid: "for (var of in of){}"
PASS Valid: "function f() { for (var of in of){} }"
PASS Invalid: "for (var of.of in of){}"
PASS Invalid: "function f() { for (var of.of in of){} }"
PASS Valid: "for (of.of in of){}"
PASS Valid: "function f() { for (of.of in of){} }"
PASS Valid: "for (of[of] in of){}"
PASS Valid: "function f() { for (of[of] in of){} }"
PASS Invalid: "for (var of[of] in of){}"
PASS Invalid: "function f() { for (var of[of] in of){} }"
PASS Valid: "for (var [of] in of){}"
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 Invalid: "for (of of of of){}"
PASS Invalid: "function f() { for (of of of of){} }"
PASS Invalid: "for (of of; of; of){}"
PASS Invalid: "function f() { for (of of; of; of){} }"
PASS Invalid: "for (of of []; of; of){}"
PASS Invalid: "function f() { for (of of []; of; of){} }"
PASS Invalid: "for (of of){}"
PASS Invalid: "function f() { for (of of){} }"
PASS Invalid: "for (var of of){}"
PASS Invalid: "function f() { for (var of of){} }"
PASS Invalid: "for (of of in of){}"
PASS Invalid: "function f() { for (of of in of){} }"
PASS Invalid: "for (of in){}"
PASS Invalid: "function f() { for (of in){} }"
PASS Invalid: "for (var of in){}"
PASS Invalid: "function f() { for (var of in){} }"
PASS e.line is 1
PASS foo is 'PASS'
PASS bar is 'PASS'
......
JSRegress/for-of-iterate-array-entries
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/for-of-iterate-array-entries.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
JSRegress/for-of-iterate-array-keys
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/for-of-iterate-array-keys.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
JSRegress/for-of-iterate-array-values
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/for-of-iterate-array-values.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
function foo() {
var array = [];
for (var i = 0; i < 25000; i++)
array.push(i);
var result = 0;
for (var [key, value] of array.entries())
result += key + value + array[key];
return result;
}
var result = foo() + foo();
if (result != 1874925000)
throw "Bad result: " + result;
function foo() {
var array = [];
for (var i = 0; i < 25000; i++)
array.push(i);
var result = 0;
for (var key of array.keys())
result += key + array[key];
return result;
}
var result = foo() + foo();
if (result != 1249950000)
throw "Bad result: " + result;
function foo() {
var array = [];
for (var i = 0; i < 25000; i++)
array.push(i);
var result = 0;
for (var i of array)
result += i;
return result;
}
var result = foo() + foo();
if (result != 624975000)
throw "Bad result: " + result;
......@@ -369,6 +369,37 @@ valid("({a: 1 || 1}.a = 1)");
invalid("var a.b = c");
invalid("var a.b;");
valid("for (of of of){}")
valid("for (of; of; of){}")
valid("for (var of of of){}")
valid("for (var of; of; of){}")
invalid("for (var of.of of of){}")
invalid("for (var of[of] of of){}")
valid("for (of.of of of){}")
valid("for (of[of] of of){}")
valid("for (var [of] of of){}")
valid("for (var {of} of of){}")
valid("for (of in of){}")
valid("for (var of in of){}")
invalid("for (var of.of in of){}")
valid("for (of.of in of){}")
valid("for (of[of] in of){}")
invalid("for (var of[of] in of){}")
valid("for (var [of] in of){}")
valid("for (var {of} in of){}")
invalid("for (of of of of){}")
invalid("for (of of; of; of){}")
invalid("for (of of []; of; of){}")
invalid("for (of of){}")
invalid("for (var of of){}")
invalid("for (of of in of){}")
invalid("for (of in){}")
invalid("for (var of in){}")
try { eval("a.b.c = {};"); } catch(e1) { e=e1; shouldBe("e.line", "1") }
foo = 'FAIL';
bar = 'PASS';
......
2013-10-04 Oliver Hunt <oliver@apple.com>
Support for-of syntax
https://bugs.webkit.org/show_bug.cgi?id=122339
Reviewed by Geoffrey Garen.
Add support for for-of syntax to JSC. As part of doing this I had to make
us support unique empty strings as identifiers. In a follow on patch i'm
going to remove the distinction entirely as it's purely a complicating
separation.
Otherwise the logic here is fairly self-explanatory.
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::addConstant):
(JSC::BytecodeGenerator::emitCall):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::CallArguments::CallArguments):
(JSC::ForOfNode::emitBytecode):
* jit/JITOperations.cpp:
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createForOfLoop):
* parser/NodeConstructors.h:
(JSC::EnumerationNode::EnumerationNode):
(JSC::ForInNode::ForInNode):
(JSC::ForOfNode::ForOfNode):
* parser/Nodes.h:
* parser/Parser.cpp:
(JSC::::parseVarDeclarationList):
(JSC::::parseForStatement):
* parser/Parser.h:
(JSC::Parser::isofToken):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createForOfLoop):
* runtime/ArrayIteratorPrototype.cpp:
(JSC::ArrayIteratorPrototype::finishCreation):
(JSC::arrayIteratorPrototypeIterate):
* runtime/ArrayPrototype.cpp:
(JSC::ArrayPrototype::create):
(JSC::ArrayPrototype::finishCreation):
* runtime/ArrayPrototype.h:
* runtime/CommonIdentifiers.cpp:
(JSC::CommonIdentifiers::CommonIdentifiers):
* runtime/CommonIdentifiers.h:
* runtime/Identifier.h:
(JSC::Identifier::from):
* runtime/JSCJSValue.cpp:
(JSC::JSValue::dumpInContext):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::reset):
* runtime/JSObject.cpp:
(JSC::JSObject::putDirectNativeFunction):
* runtime/PrivateName.h:
(JSC::PrivateName::PrivateName):
* runtime/PropertyName.h:
(JSC::PropertyName::PropertyName):
2013-10-04 Michael Saboff <msaboff@apple.com>
FTL::OSRExit::convertToForward() shouldn't misuse Operands<>::operator[]
......@@ -957,7 +957,7 @@ unsigned BytecodeGenerator::addConstant(const Identifier& ident)
StringImpl* rep = ident.impl();
IdentifierMap::AddResult result = m_identifierMap.add(rep, m_codeBlock->numberOfIdentifiers());
if (result.isNewEntry)
m_codeBlock->addIdentifier(Identifier(m_vm, rep));
m_codeBlock->addIdentifier(ident);
return result.iterator->value;
}
......@@ -1693,9 +1693,11 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi
// Generate code for arguments.
unsigned argument = 0;
for (ArgumentListNode* n = callArguments.argumentsNode()->m_listNode; n; n = n->m_next)
emitNode(callArguments.argumentRegister(argument++), n);
if (callArguments.argumentsNode()) {
for (ArgumentListNode* n = callArguments.argumentsNode()->m_listNode; n; n = n->m_next)
emitNode(callArguments.argumentRegister(argument++), n);
}
// Reserve space for call frame.
Vector<RefPtr<RegisterID>, JSStack::CallFrameHeaderSize, UnsafeVectorOverflow> callFrame;
for (int i = 0; i < JSStack::CallFrameHeaderSize; ++i)
......
......@@ -62,7 +62,7 @@ namespace JSC {
class CallArguments {
public:
CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode);
CallArguments(BytecodeGenerator&, ArgumentsNode*, unsigned additionalArguments = 0);
RegisterID* thisRegister() { return m_argv[0].get(); }
RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); }
......
......@@ -379,13 +379,13 @@ RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID*
return generator.emitConstruct(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd());
}
inline CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode)
inline CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode, unsigned additionalArguments)
: m_argumentsNode(argumentsNode)
{
if (generator.shouldEmitProfileHooks())
m_profileHookRegister = generator.newTemporary();
size_t argumentCountIncludingThis = 1; // 'this' register.
size_t argumentCountIncludingThis = 1 + additionalArguments; // 'this' register.
if (argumentsNode) {
for (ArgumentListNode* node = argumentsNode->m_listNode; node; node = node->m_next)
++argumentCountIncludingThis;
......@@ -1759,6 +1759,81 @@ void ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
generator.emitLabel(scope->breakTarget());
}
// ------------------------------ ForOfNode ------------------------------------
void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop);
if (!m_lexpr->isLocation()) {
emitThrowReferenceError(generator, "Left side of for-of statement is not a reference.");
return;
}
generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset());
RefPtr<RegisterID> subject = generator.emitNode(m_expr);
RefPtr<RegisterID> iterator = generator.emitGetById(generator.newTemporary(), subject.get(), generator.propertyNames().iteratorPrivateName);
{
CallArguments args(generator, 0);
generator.emitMove(args.thisRegister(), subject.get());
generator.emitCall(iterator.get(), iterator.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd());
}
RefPtr<RegisterID> iteratorNext = generator.emitGetById(generator.newTemporary(), iterator.get(), generator.propertyNames().next);
RefPtr<RegisterID> value = generator.newTemporary();
generator.emitLoad(value.get(), jsUndefined());
generator.emitJump(scope->continueTarget());
RefPtr<Label> loopStart = generator.newLabel();
generator.emitLabel(loopStart.get());
generator.emitLoopHint();
if (m_lexpr->isResolveNode()) {
const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier();
if (Local local = generator.local(ident))
generator.emitMove(local.get(), value.get());
else {
if (generator.isStrictMode())
generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident);
generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
generator.emitPutToScope(scope, ident, value.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
}
} else if (m_lexpr->isDotAccessorNode()) {
DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr);
const Identifier& ident = assignNode->identifier();
RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
generator.emitPutById(base.get(), ident, value.get());
} else if (m_lexpr->isBracketAccessorNode()) {
BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr);
RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
RegisterID* subscript = generator.emitNode(assignNode->subscript());
generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
generator.emitPutByVal(base.get(), subscript, value.get());
} else {
ASSERT(m_lexpr->isDeconstructionNode());
DeconstructingAssignmentNode* assignNode = static_cast<DeconstructingAssignmentNode*>(m_lexpr);
assignNode->bindings()->emitBytecode(generator, value.get());
}
generator.emitNode(dst, m_statement);
generator.emitLabel(scope->continueTarget());
RefPtr<RegisterID> result = generator.newTemporary();
CallArguments nextArguments(generator, 0, 1);
generator.emitMove(nextArguments.thisRegister(), iterator.get());
generator.emitMove(nextArguments.argumentRegister(0), value.get());
generator.emitCall(result.get(), iteratorNext.get(), NoExpectedFunction, nextArguments, divot(), divotStart(), divotEnd());
generator.emitGetById(value.get(), result.get(), generator.propertyNames().value);
RefPtr<RegisterID> done = generator.emitGetById(generator.newTemporary(), result.get(), generator.propertyNames().done);
generator.emitJumpIfFalse(done.get(), loopStart.get());
generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset());
generator.emitLabel(scope->breakTarget());
}
// ------------------------------ ContinueNode ---------------------------------
Label* ContinueNode::trivialTarget(BytecodeGenerator& generator)
......
......@@ -74,8 +74,7 @@ EncodedJSValue JIT_OPERATION operationGetByIdOptimizeWithReturnAddress(ExecState
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
Identifier ident(vm, uid);
Identifier ident = uid->isEmptyUnique() ? Identifier::from(PrivateName(uid)) : Identifier(vm, uid);
StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
......
......@@ -380,6 +380,22 @@ public:
setExceptionLocation(result, eStart, eDivot, eEnd);
return result;
}
StatementNode* createForOfLoop(const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end)
{
ForOfNode* result = new (m_vm) ForOfNode(location, lhs, iter, statements);
result->setLoc(start, end, location.startOffset, location.lineStartOffset);
setExceptionLocation(result, eStart, eDivot, eEnd);
return result;
}
StatementNode* createForOfLoop(const JSTokenLocation& location, PassRefPtr<DeconstructionPatternNode> pattern, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end)
{
ForOfNode* result = new (m_vm) ForOfNode(m_vm, location, pattern.get(), iter, statements);
result->setLoc(start, end, location.startOffset, location.lineStartOffset);
setExceptionLocation(result, eStart, eDivot, eEnd);
return result;
}
StatementNode* createEmptyStatement(const JSTokenLocation& location) { return new (m_vm) EmptyStatementNode(location); }
......
......@@ -811,7 +811,7 @@ inline ResolveNode::ResolveNode(const JSTokenLocation& location, const Identifie
{
}
inline ForInNode::ForInNode(const JSTokenLocation& location, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
inline EnumerationNode::EnumerationNode(const JSTokenLocation& location, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
: StatementNode(location)
, m_lexpr(l)
, m_expr(expr)
......@@ -820,7 +820,7 @@ inline ResolveNode::ResolveNode(const JSTokenLocation& location, const Identifie
ASSERT(l);
}
inline ForInNode::ForInNode(VM* vm, const JSTokenLocation& location, DeconstructionPatternNode* pattern, ExpressionNode* expr, StatementNode* statement)
inline EnumerationNode::EnumerationNode(VM* vm, const JSTokenLocation& location, DeconstructionPatternNode* pattern, ExpressionNode* expr, StatementNode* statement)
: StatementNode(location)
, m_lexpr(new (vm) DeconstructingAssignmentNode(location, pattern, 0))
, m_expr(expr)
......@@ -829,6 +829,26 @@ inline ResolveNode::ResolveNode(const JSTokenLocation& location, const Identifie
ASSERT(pattern);
}
inline ForInNode::ForInNode(const JSTokenLocation& location, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
: EnumerationNode(location, l, expr, statement)
{
}
inline ForInNode::ForInNode(VM* vm, const JSTokenLocation& location, DeconstructionPatternNode* pattern, ExpressionNode* expr, StatementNode* statement)
: EnumerationNode(vm, location, pattern, expr, statement)
{
}
inline ForOfNode::ForOfNode(const JSTokenLocation& location, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
: EnumerationNode(location, l, expr, statement)
{
}
inline ForOfNode::ForOfNode(VM* vm, const JSTokenLocation& location, DeconstructionPatternNode* pattern, ExpressionNode* expr, StatementNode* statement)
: EnumerationNode(vm, location, pattern, expr, statement)
{
}
inline DeconstructionPatternNode::DeconstructionPatternNode(VM*)
{
}
......
......@@ -1242,18 +1242,34 @@ namespace JSC {
};
class DeconstructionPatternNode;
class ForInNode : public StatementNode, public ThrowableExpressionData {
class EnumerationNode : public StatementNode, public ThrowableExpressionData {
public:
EnumerationNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*);
EnumerationNode(VM*, const JSTokenLocation&, DeconstructionPatternNode*, ExpressionNode*, StatementNode*);
protected:
ExpressionNode* m_lexpr;
ExpressionNode* m_expr;
StatementNode* m_statement;
};
class ForInNode : public EnumerationNode {
public:
ForInNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*);
ForInNode(VM*, const JSTokenLocation&, DeconstructionPatternNode*, ExpressionNode*, StatementNode*);
private:
virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0);
ExpressionNode* m_lexpr;
ExpressionNode* m_expr;
StatementNode* m_statement;
};
class ForOfNode : public EnumerationNode {
public:
ForOfNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*);
ForOfNode(VM*, const JSTokenLocation&, DeconstructionPatternNode*, ExpressionNode*, StatementNode*);
private:
virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0);
};
class ContinueNode : public StatementNode, public ThrowableExpressionData {
......
......@@ -294,7 +294,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarati
next();
hasInitializer = match(EQUAL);
failIfFalseIfStrictWithNameAndMessage(declareVariable(name), "Cannot declare a variable named", name->impl(), "in strict mode.");
context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
context.addVar(name, (hasInitializer || (!m_allowsIn && (match(INTOKEN) || isofToken()))) ? DeclarationStacks::HasInitializer : 0);
if (hasInitializer) {
JSTextPosition varDivot = tokenStartPosition() + 1;
initStart = tokenStartPosition();
......@@ -317,7 +317,6 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarati
TreeExpression rhs = parseExpression(context);
node = context.createDeconstructingAssignment(location, pattern, rhs);
}
ASSERT(node);
}
if (hasInitializer) {
......@@ -501,7 +500,12 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(
// Handle for-in with var declaration
JSTextPosition inLocation = tokenStartPosition();