Implement prefixed-destructuring assignment
https://bugs.webkit.org/show_bug.cgi?id=121930
Reviewed by Mark Hahnenberg.
Source/JavaScriptCore:
Relanding with fix after rollout - it helps to not completely destroy
optimisations for no reason.
LayoutTests:
Relanding with fix after rollout - it helps to not completely destroy
optimisations for no reason.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@156785 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index b8663e2..1669635 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,13 @@
+2013-09-25 Oliver Hunt <oliver@apple.com>
+
+ Implement prefixed-destructuring assignment
+ https://bugs.webkit.org/show_bug.cgi?id=121930
+
+ Reviewed by Mark Hahnenberg.
+
+ Relanding with fix after rollout - it helps to not completely destroy
+ optimisations for no reason.
+
2013-10-02 Nadav Rotem <nrotem@apple.com>
FTL: Refactor compileArithDiv and compileArithMod into one function.
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
index c4067e3..d13aa65 100644
--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
@@ -183,7 +183,7 @@
for (size_t pos = 0; pos < parameters.size(); ++pos) {
if (!builder.isEmpty())
builder.appendLiteral(", ");
- builder.append(parameters.at(pos).string());
+ parameters.at(pos)->toString(builder);
}
return builder.toString();
}
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index be0fcb3..c9632eb 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -180,7 +180,7 @@
}
for (size_t i = 0; i < varStack.size(); ++i)
- codeBlock->addVariableDeclaration(*varStack[i].first, !!(varStack[i].second & DeclarationStacks::IsConstant));
+ codeBlock->addVariableDeclaration(varStack[i].first, !!(varStack[i].second & DeclarationStacks::IsConstant));
}
@@ -215,6 +215,15 @@
m_codeBlock->setNeedsFullScopeChain(true);
m_symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode());
+ Vector<Identifier> boundParameterProperties;
+ FunctionParameters& parameters = *functionBody->parameters();
+ for (size_t i = 0; i < parameters.size(); i++) {
+ auto pattern = parameters.at(i);
+ if (pattern->isBindingNode())
+ continue;
+ pattern->collectBoundIdentifiers(boundParameterProperties);
+ continue;
+ }
m_symbolTable->setParameterCountIncludingThis(functionBody->parameters()->size() + 1);
emitOpcode(op_enter);
@@ -254,7 +263,11 @@
capturedArguments.resize(parameters.size());
for (size_t i = 0; i < parameters.size(); ++i) {
capturedArguments[i] = 0;
- if (!functionBody->captures(parameters.at(i)) && !shouldCaptureAllTheThings)
+ auto pattern = parameters.at(i);
+ if (!pattern->isBindingNode())
+ continue;
+ const Identifier& ident = static_cast<const BindingNode*>(pattern)->boundProperty();
+ if (!functionBody->captures(ident) && !shouldCaptureAllTheThings)
continue;
capturesAnyArgumentByName = true;
capturedArguments[i] = addVar();
@@ -299,7 +312,7 @@
}
}
for (size_t i = 0; i < varStack.size(); ++i) {
- const Identifier& ident = *varStack[i].first;
+ const Identifier& ident = varStack[i].first;
if (functionBody->captures(ident))
addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
}
@@ -332,7 +345,7 @@
}
m_lastLazyFunction = canLazilyCreateFunctions ? codeBlock->m_numVars : m_firstLazyFunction;
for (size_t i = 0; i < varStack.size(); ++i) {
- const Identifier& ident = *varStack[i].first;
+ const Identifier& ident = varStack[i].first;
if (!functionBody->captures(ident))
addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
}
@@ -340,23 +353,31 @@
if (shouldCaptureAllTheThings)
m_symbolTable->setCaptureEnd(virtualRegisterForLocal(codeBlock->m_numVars).offset());
- FunctionParameters& parameters = *functionBody->parameters();
m_parameters.grow(parameters.size() + 1); // reserve space for "this"
// Add "this" as a parameter
int nextParameterIndex = CallFrame::thisArgumentOffset();
m_thisRegister.setIndex(nextParameterIndex++);
m_codeBlock->addParameter();
-
+ Vector<std::pair<RegisterID*, const DeconstructionPatternNode*>> deconstructedParameters;
for (size_t i = 0; i < parameters.size(); ++i, ++nextParameterIndex) {
int index = nextParameterIndex;
+ auto pattern = parameters.at(i);
+ if (!pattern->isBindingNode()) {
+ m_codeBlock->addParameter();
+ RegisterID& parameter = registerFor(index);
+ parameter.setIndex(index);
+ deconstructedParameters.append(make_pair(¶meter, pattern));
+ continue;
+ }
+ auto simpleParameter = static_cast<const BindingNode*>(pattern);
if (capturedArguments.size() && capturedArguments[i]) {
- ASSERT((functionBody->hasCapturedVariables() && functionBody->captures(parameters.at(i))) || shouldCaptureAllTheThings);
+ ASSERT((functionBody->hasCapturedVariables() && functionBody->captures(simpleParameter->boundProperty())) || shouldCaptureAllTheThings);
index = capturedArguments[i]->index();
RegisterID original(nextParameterIndex);
emitMove(capturedArguments[i], &original);
}
- addParameter(parameters.at(i), index);
+ addParameter(simpleParameter->boundProperty(), index);
}
preserveLastVar();
@@ -370,6 +391,10 @@
instructions().append(kill(&m_thisRegister));
instructions().append(0);
}
+ for (size_t i = 0; i < deconstructedParameters.size(); i++) {
+ auto& entry = deconstructedParameters[i];
+ entry.second->emitBytecode(*this, entry.first);
+ }
}
BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
@@ -414,8 +439,10 @@
unsigned numVariables = varStack.size();
Vector<Identifier, 0, UnsafeVectorOverflow> variables;
variables.reserveCapacity(numVariables);
- for (size_t i = 0; i < numVariables; ++i)
- variables.append(*varStack[i].first);
+ for (size_t i = 0; i < numVariables; ++i) {
+ ASSERT(varStack[i].first.impl()->isIdentifier());
+ variables.append(varStack[i].first);
+ }
codeBlock->adoptVariables(variables);
preserveLastVar();
}
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 06c0fe4..fcc17df 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -286,7 +286,10 @@
lineStart -= sourceOffset;
else
lineStart = 0;
- ASSERT(divotOffset >= lineStart);
+
+ if (divotOffset < lineStart)
+ return;
+
unsigned column = divotOffset - lineStart;
unsigned instructionOffset = instructions().size();
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 633b296..7410216 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -35,6 +35,7 @@
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "JSNameScope.h"
+#include "JSONObject.h"
#include "LabelScope.h"
#include "Lexer.h"
#include "Operations.h"
@@ -1713,8 +1714,7 @@
generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
generator.emitPutById(base, ident, propertyName);
- } else {
- ASSERT(m_lexpr->isBracketAccessorNode());
+ } else if (m_lexpr->isBracketAccessorNode()) {
BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr);
propertyName = generator.newTemporary();
RefPtr<RegisterID> protect = propertyName;
@@ -1723,7 +1723,30 @@
generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
generator.emitPutByVal(base.get(), subscript, propertyName);
- }
+ } else {
+ ASSERT(m_lexpr->isDeconstructionNode());
+ DeconstructingAssignmentNode* assignNode = static_cast<DeconstructingAssignmentNode*>(m_lexpr);
+ auto binding = assignNode->bindings();
+ if (binding->isBindingNode()) {
+ auto simpleBinding = static_cast<BindingNode*>(binding);
+ Identifier ident = simpleBinding->boundProperty();
+ Local local = generator.local(ident);
+ propertyName = local.get();
+ if (!propertyName)
+ goto genericBinding;
+ expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName);
+ generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName);
+ optimizedForinAccess = true;
+ goto completedSimpleBinding;
+ } else {
+ genericBinding:
+ propertyName = generator.newTemporary();
+ RefPtr<RegisterID> protect(propertyName);
+ assignNode->bindings()->emitBytecode(generator, propertyName);
+ }
+ completedSimpleBinding:
+ ;
+ }
generator.emitNode(dst, m_statement);
@@ -2179,5 +2202,157 @@
{
return generator.emitNewFunctionExpression(generator.finalDestination(dst), this);
}
+
+// ------------------------------ DeconstructingAssignmentNode -----------------
+RegisterID* DeconstructingAssignmentNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+ if (RegisterID* result = m_bindings->emitDirectBinding(generator, dst, m_initializer))
+ return result;
+ RefPtr<RegisterID> initializer = generator.tempDestination(dst);
+ generator.emitNode(initializer.get(), m_initializer);
+ m_bindings->emitBytecode(generator, initializer.get());
+ return generator.moveToDestinationIfNeeded(dst, initializer.get());
+}
+
+DeconstructionPatternNode::~DeconstructionPatternNode()
+{
+}
+
+void ArrayPatternNode::emitBytecode(BytecodeGenerator& generator, RegisterID* rhs) const
+{
+ for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+ auto target = m_targetPatterns[i];
+ if (!target)
+ continue;
+ RefPtr<RegisterID> temp = generator.newTemporary();
+ generator.emitLoad(temp.get(), jsNumber(i));
+ generator.emitGetByVal(temp.get(), rhs, temp.get());
+ target->emitBytecode(generator, temp.get());
+ }
+}
+
+RegisterID* ArrayPatternNode::emitDirectBinding(BytecodeGenerator& generator, RegisterID* dst, ExpressionNode* rhs)
+{
+ if (rhs->isResolveNode()
+ && generator.willResolveToArguments(static_cast<ResolveNode*>(rhs)->identifier())
+ && !generator.symbolTable().slowArguments()) {
+ for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+ auto target = m_targetPatterns[i];
+ if (!target)
+ continue;
+
+ RefPtr<RegisterID> temp = generator.newTemporary();
+ generator.emitLoad(temp.get(), jsNumber(i));
+ generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), temp.get());
+ target->emitBytecode(generator, temp.get());
+ }
+ }
+ if (!rhs->isSimpleArray())
+ return 0;
+ ElementNode* elementNodes = static_cast<ArrayNode*>(rhs)->elements();
+ Vector<ExpressionNode*> elements;
+ for (; elementNodes; elementNodes = elementNodes->next())
+ elements.append(elementNodes->value());
+ if (m_targetPatterns.size() != elements.size())
+ return 0;
+ Vector<RefPtr<RegisterID>> registers;
+ registers.reserveCapacity(m_targetPatterns.size());
+ for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+ registers.uncheckedAppend(generator.newTemporary());
+ generator.emitNode(registers.last().get(), elements[i]);
+ }
+
+ for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+ if (m_targetPatterns[i])
+ m_targetPatterns[i]->emitBytecode(generator, registers[i].get());
+ }
+ RefPtr<RegisterID> result = generator.finalDestination(dst);
+ return generator.emitLoad(result.get(), jsUndefined());
+}
+
+void ArrayPatternNode::toString(StringBuilder& builder) const
+{
+ builder.append('[');
+ for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+ if (!m_targetPatterns[i]) {
+ builder.append(',');
+ continue;
+ }
+ m_targetPatterns[i]->toString(builder);
+ if (i < m_targetPatterns.size() - 1)
+ builder.append(',');
+ }
+ builder.append(']');
+}
+
+void ArrayPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const
+{
+ for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+ if (DeconstructionPatternNode* node = m_targetPatterns[i].get())
+ node->collectBoundIdentifiers(identifiers);
+ }
+}
+
+void ObjectPatternNode::toString(StringBuilder& builder) const
+{
+ builder.append('{');
+ for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+ if (m_targetPatterns[i].wasString) {
+ builder.append('"');
+ escapeStringToBuilder(builder, m_targetPatterns[i].propertyName.string());
+ builder.append('"');
+ } else
+ builder.append(m_targetPatterns[i].propertyName.string());
+ builder.append(":");
+ m_targetPatterns[i].pattern->toString(builder);
+ if (i < m_targetPatterns.size() - 1)
+ builder.append(',');
+ }
+ builder.append('}');
+}
+
+void ObjectPatternNode::emitBytecode(BytecodeGenerator& generator, RegisterID* rhs) const
+{
+ for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+ auto& target = m_targetPatterns[i];
+ RefPtr<RegisterID> temp = generator.newTemporary();
+ generator.emitGetById(temp.get(), rhs, target.propertyName);
+ target.pattern->emitBytecode(generator, temp.get());
+ }
+}
+
+void ObjectPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const
+{
+ for (size_t i = 0; i < m_targetPatterns.size(); i++)
+ m_targetPatterns[i].pattern->collectBoundIdentifiers(identifiers);
+}
+
+void BindingNode::emitBytecode(BytecodeGenerator& generator, RegisterID* value) const
+{
+ if (Local local = generator.local(m_boundProperty)) {
+ if (local.isReadOnly()) {
+ generator.emitReadOnlyExceptionIfNeeded();
+ return;
+ }
+ generator.emitMove(local.get(), value);
+ return;
+ }
+ if (generator.isStrictMode())
+ generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
+ RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), m_boundProperty);
+ generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
+ generator.emitPutToScope(scope, m_boundProperty, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
+ return;
+}
+
+void BindingNode::toString(StringBuilder& builder) const
+{
+ builder.append(m_boundProperty.string());
+}
+
+void BindingNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const
+{
+ identifiers.append(m_boundProperty);
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/parser/ASTBuilder.h b/Source/JavaScriptCore/parser/ASTBuilder.h
index 95c98d0..a37cdc7 100644
--- a/Source/JavaScriptCore/parser/ASTBuilder.h
+++ b/Source/JavaScriptCore/parser/ASTBuilder.h
@@ -90,6 +90,7 @@
UnaryExprContext(ASTBuilder&) {}
};
+
typedef SyntaxChecker FunctionBodyBuilder;
typedef ExpressionNode* Expression;
@@ -107,7 +108,10 @@
typedef CaseClauseNode* Clause;
typedef ConstDeclNode* ConstDeclList;
typedef std::pair<ExpressionNode*, BinaryOpInfo> BinaryOperand;
-
+ typedef RefPtr<DeconstructionPatternNode> DeconstructionPattern;
+ typedef RefPtr<ArrayPatternNode> ArrayPattern;
+ typedef RefPtr<ObjectPatternNode> ObjectPattern;
+ typedef RefPtr<BindingNode> BindingPattern;
static const bool CreatesAST = true;
static const bool NeedsFreeVariableInfo = true;
static const bool CanUseFunctionCache = true;
@@ -314,8 +318,8 @@
ElementNode* createElementList(int elisions, ExpressionNode* expr) { return new (m_vm) ElementNode(elisions, expr); }
ElementNode* createElementList(ElementNode* elems, int elisions, ExpressionNode* expr) { return new (m_vm) ElementNode(elems, elisions, expr); }
- ParameterNode* createFormalParameterList(const Identifier& ident) { return new (m_vm) ParameterNode(ident); }
- ParameterNode* createFormalParameterList(ParameterNode* list, const Identifier& ident) { return new (m_vm) ParameterNode(list, ident); }
+ ParameterNode* createFormalParameterList(DeconstructionPattern pattern) { return new (m_vm) ParameterNode(pattern); }
+ ParameterNode* createFormalParameterList(ParameterNode* list, DeconstructionPattern pattern) { return new (m_vm) ParameterNode(list, pattern); }
CaseClauseNode* createClause(ExpressionNode* expr, JSC::SourceElements* statements) { return new (m_vm) CaseClauseNode(expr, statements); }
ClauseListNode* createClauseList(CaseClauseNode* clause) { return new (m_vm) ClauseListNode(clause); }
@@ -361,14 +365,6 @@
return result;
}
- StatementNode* createForInLoop(const JSTokenLocation& location, const Identifier* ident, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end, int startLine, int endLine)
- {
- ForInNode* result = new (m_vm) ForInNode(m_vm, location, *ident, iter, statements, start);
- result->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
- setExceptionLocation(result, start, divot + 1, end);
- return result;
- }
-
StatementNode* createForInLoop(const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end)
{
ForInNode* result = new (m_vm) ForInNode(location, lhs, iter, statements);
@@ -376,6 +372,14 @@
setExceptionLocation(result, eStart, eDivot, eEnd);
return result;
}
+
+ StatementNode* createForInLoop(const JSTokenLocation& location, PassRefPtr<DeconstructionPatternNode> pattern, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end)
+ {
+ ForInNode* result = new (m_vm) ForInNode(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); }
@@ -515,7 +519,8 @@
{
if (m_vm->propertyNames->arguments == *ident)
usesArguments();
- m_scope.m_varDeclarations->data.append(std::make_pair(ident, attrs));
+ ASSERT(ident->impl()->isIdentifier());
+ m_scope.m_varDeclarations->data.append(std::make_pair(*ident, attrs));
}
ExpressionNode* combineCommaNodes(const JSTokenLocation& location, ExpressionNode* list, ExpressionNode* init)
@@ -615,6 +620,41 @@
bool isResolve(ExpressionNode* expr) const { return expr->isResolveNode(); }
+ ExpressionNode* createDeconstructingAssignment(const JSTokenLocation& location, PassRefPtr<DeconstructionPatternNode> pattern, ExpressionNode* initializer)
+ {
+ return new (m_vm) DeconstructingAssignmentNode(location, pattern.get(), initializer);
+ }
+
+ ArrayPattern createArrayPattern(const JSTokenLocation&)
+ {
+ return ArrayPatternNode::create(m_vm);
+ }
+
+ void appendArrayPatternSkipEntry(ArrayPattern node, const JSTokenLocation& location)
+ {
+ node->appendIndex(location, 0);
+ }
+
+ void appendArrayPatternEntry(ArrayPattern node, const JSTokenLocation& location, DeconstructionPattern pattern)
+ {
+ node->appendIndex(location, pattern.get());
+ }
+
+ ObjectPattern createObjectPattern(const JSTokenLocation&)
+ {
+ return ObjectPatternNode::create(m_vm);
+ }
+
+ void appendObjectPatternEntry(ObjectPattern node, const JSTokenLocation& location, bool wasString, const Identifier& identifier, DeconstructionPattern pattern)
+ {
+ node->appendEntry(location, identifier, wasString, pattern.get());
+ }
+
+ BindingPattern createBindingLocation(const JSTokenLocation&, const Identifier& boundProperty, const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end)
+ {
+ return BindingNode::create(m_vm, boundProperty, divot, start, end);
+ }
+
private:
struct Scope {
Scope(VM* vm)
diff --git a/Source/JavaScriptCore/parser/NodeConstructors.h b/Source/JavaScriptCore/parser/NodeConstructors.h
index 5ccc779..0ce20eb 100644
--- a/Source/JavaScriptCore/parser/NodeConstructors.h
+++ b/Source/JavaScriptCore/parser/NodeConstructors.h
@@ -603,6 +603,8 @@
inline CommaNode::CommaNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2)
: ExpressionNode(location)
{
+ ASSERT(expr1);
+ ASSERT(expr2);
m_expressions.append(expr1);
m_expressions.append(expr2);
}
@@ -732,17 +734,20 @@
{
}
- inline ParameterNode::ParameterNode(const Identifier& ident)
- : m_ident(ident)
+ inline ParameterNode::ParameterNode(PassRefPtr<DeconstructionPatternNode> pattern)
+ : m_pattern(pattern)
, m_next(0)
{
+ ASSERT(m_pattern);
}
- inline ParameterNode::ParameterNode(ParameterNode* l, const Identifier& ident)
- : m_ident(ident)
+ inline ParameterNode::ParameterNode(ParameterNode* l, PassRefPtr<DeconstructionPatternNode> pattern)
+ : m_pattern(pattern)
, m_next(0)
{
l->m_next = this;
+ ASSERT(m_pattern);
+ ASSERT(l->m_pattern);
}
inline FuncExprNode::FuncExprNode(const JSTokenLocation& location, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter)
@@ -812,16 +817,61 @@
, m_expr(expr)
, m_statement(statement)
{
+ ASSERT(l);
}
-
- inline ForInNode::ForInNode(VM* vm, const JSTokenLocation& location, const Identifier& ident, ExpressionNode* expr, StatementNode* statement, const JSTextPosition& divotStart)
+
+ inline ForInNode::ForInNode(VM* vm, const JSTokenLocation& location, DeconstructionPatternNode* pattern, ExpressionNode* expr, StatementNode* statement)
: StatementNode(location)
- , m_lexpr(new (vm) ResolveNode(location, ident, divotStart))
+ , m_lexpr(new (vm) DeconstructingAssignmentNode(location, pattern, 0))
, m_expr(expr)
, m_statement(statement)
{
+ ASSERT(pattern);
+ }
+
+ inline DeconstructionPatternNode::DeconstructionPatternNode(VM*)
+ {
}
+ inline ArrayPatternNode::ArrayPatternNode(VM* vm)
+ : DeconstructionPatternNode(vm)
+ {
+ }
+
+ inline PassRefPtr<ArrayPatternNode> ArrayPatternNode::create(VM* vm)
+ {
+ return adoptRef(new ArrayPatternNode(vm));
+ }
+
+ inline ObjectPatternNode::ObjectPatternNode(VM* vm)
+ : DeconstructionPatternNode(vm)
+ {
+ }
+
+ inline PassRefPtr<ObjectPatternNode> ObjectPatternNode::create(VM* vm)
+ {
+ return adoptRef(new ObjectPatternNode(vm));
+ }
+
+ inline PassRefPtr<BindingNode> BindingNode::create(VM* vm, const Identifier& boundProperty, const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end)
+ {
+ return adoptRef(new BindingNode(vm, boundProperty, divot, start, end));
+ }
+
+ inline BindingNode::BindingNode(VM* vm, const Identifier& boundProperty, const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end)
+ : DeconstructionPatternNode(vm)
+ , ThrowableExpressionData(divot, start, end)
+ , m_boundProperty(boundProperty)
+ {
+ }
+
+ inline DeconstructingAssignmentNode::DeconstructingAssignmentNode(const JSTokenLocation& location, PassRefPtr<DeconstructionPatternNode> bindings, ExpressionNode* initializer)
+ : ExpressionNode(location)
+ , m_bindings(bindings)
+ , m_initializer(initializer)
+ {
+ }
+
} // namespace JSC
#endif // NodeConstructors_h
diff --git a/Source/JavaScriptCore/parser/Nodes.cpp b/Source/JavaScriptCore/parser/Nodes.cpp
index 36ded3863..d8ddeaf 100644
--- a/Source/JavaScriptCore/parser/Nodes.cpp
+++ b/Source/JavaScriptCore/parser/Nodes.cpp
@@ -157,7 +157,7 @@
for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam())
++parameterCount;
- size_t objectSize = sizeof(FunctionParameters) - sizeof(void*) + sizeof(StringImpl*) * parameterCount;
+ size_t objectSize = sizeof(FunctionParameters) - sizeof(void*) + sizeof(DeconstructionPatternNode*) * parameterCount;
void* slot = fastMalloc(objectSize);
return adoptRef(new (slot) FunctionParameters(firstParameter, parameterCount));
}
@@ -166,14 +166,17 @@
: m_size(size)
{
unsigned i = 0;
- for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam())
- new (&identifiers()[i++]) Identifier(parameter->ident());
+ for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam()) {
+ auto pattern = parameter->pattern();
+ pattern->ref();
+ patterns()[i++] = pattern;
+ }
}
FunctionParameters::~FunctionParameters()
{
for (unsigned i = 0; i < m_size; ++i)
- identifiers()[i].~Identifier();
+ patterns()[i]->deref();
}
inline FunctionBodyNode::FunctionBodyNode(VM* vm, const JSTokenLocation& startLocation, const JSTokenLocation& endLocation, unsigned startColumn, bool inStrictContext)
diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h
index d7bf28e..e702e3f 100644
--- a/Source/JavaScriptCore/parser/Nodes.h
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -80,7 +80,7 @@
namespace DeclarationStacks {
enum VarAttrs { IsConstant = 1, HasInitializer = 2 };
- typedef Vector<std::pair<const Identifier*, unsigned> > VarStack;
+ typedef Vector<std::pair<Identifier, unsigned> > VarStack;
typedef Vector<FunctionBodyNode*> FunctionStack;
}
@@ -154,6 +154,7 @@
virtual bool isResolveNode() const { return false; }
virtual bool isBracketAccessorNode() const { return false; }
virtual bool isDotAccessorNode() const { return false; }
+ virtual bool isDeconstructionNode() const { return false; }
virtual bool isFuncExprNode() const { return false; }
virtual bool isCommaNode() const { return false; }
virtual bool isSimpleArray() const { return false; }
@@ -461,6 +462,7 @@
ArgumentListNode* toArgumentList(VM*, int, int) const;
+ ElementNode* elements() const { ASSERT(isSimpleArray()); return m_element; }
private:
virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
@@ -1080,7 +1082,7 @@
using ParserArenaDeletable::operator new;
- void append(ExpressionNode* expr) { m_expressions.append(expr); }
+ void append(ExpressionNode* expr) { ASSERT(expr); m_expressions.append(expr); }
private:
virtual bool isCommaNode() const { return true; }
@@ -1238,11 +1240,13 @@
ExpressionNode* m_expr3;
StatementNode* m_statement;
};
+
+ class DeconstructionPatternNode;
class ForInNode : public StatementNode, public ThrowableExpressionData {
public:
ForInNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*);
- ForInNode(VM*, const JSTokenLocation&, const Identifier&, ExpressionNode*, StatementNode*, const JSTextPosition& divotStart);
+ ForInNode(VM*, const JSTokenLocation&, DeconstructionPatternNode*, ExpressionNode*, StatementNode*);
private:
virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0);
@@ -1341,14 +1345,14 @@
class ParameterNode : public ParserArenaDeletable {
public:
- ParameterNode(const Identifier&);
- ParameterNode(ParameterNode*, const Identifier&);
+ ParameterNode(PassRefPtr<DeconstructionPatternNode>);
+ ParameterNode(ParameterNode*, PassRefPtr<DeconstructionPatternNode>);
- const Identifier& ident() const { return m_ident; }
+ DeconstructionPatternNode* pattern() const { return m_pattern.get(); }
ParameterNode* nextParam() const { return m_next; }
private:
- const Identifier& m_ident;
+ RefPtr<DeconstructionPatternNode> m_pattern;
ParameterNode* m_next;
};
@@ -1460,21 +1464,21 @@
class FunctionParameters : public RefCounted<FunctionParameters> {
WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_NONCOPYABLE(FunctionParameters);
public:
static PassRefPtr<FunctionParameters> create(ParameterNode*);
~FunctionParameters();
unsigned size() const { return m_size; }
- const Identifier& at(unsigned index) const { ASSERT(index < m_size); return identifiers()[index]; }
+ DeconstructionPatternNode* at(unsigned index) { ASSERT(index < m_size); return patterns()[index]; }
private:
FunctionParameters(ParameterNode*, unsigned size);
- Identifier* identifiers() { return reinterpret_cast<Identifier*>(&m_storage); }
- const Identifier* identifiers() const { return reinterpret_cast<const Identifier*>(&m_storage); }
+ DeconstructionPatternNode** patterns() { return &m_storage; }
unsigned m_size;
- void* m_storage;
+ DeconstructionPatternNode* m_storage;
};
class FunctionBodyNode : public ScopeNode {
@@ -1530,6 +1534,102 @@
FunctionBodyNode* m_body;
};
+ class DeconstructionPatternNode : public RefCounted<DeconstructionPatternNode> {
+ WTF_MAKE_NONCOPYABLE(DeconstructionPatternNode);
+ WTF_MAKE_FAST_ALLOCATED;
+
+ public:
+ virtual void collectBoundIdentifiers(Vector<Identifier>&) const = 0;
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* source) const = 0;
+ virtual void toString(StringBuilder&) const = 0;
+
+ virtual bool isBindingNode() const { return false; }
+ virtual RegisterID* emitDirectBinding(BytecodeGenerator&, RegisterID*, ExpressionNode*) { return 0; }
+
+ virtual ~DeconstructionPatternNode() = 0;
+
+ protected:
+ DeconstructionPatternNode(VM*);
+ };
+
+ class ArrayPatternNode : public DeconstructionPatternNode {
+ public:
+ static PassRefPtr<ArrayPatternNode> create(VM*);
+ void appendIndex(const JSTokenLocation&, DeconstructionPatternNode* node)
+ {
+ m_targetPatterns.append(node);
+ }
+
+ private:
+ ArrayPatternNode(VM*);
+ void collectBoundIdentifiers(Vector<Identifier>&) const;
+ void emitBytecode(BytecodeGenerator&, RegisterID*) const;
+ RegisterID* emitDirectBinding(BytecodeGenerator&, RegisterID* dst, ExpressionNode*);
+ void toString(StringBuilder&) const;
+
+ Vector<RefPtr<DeconstructionPatternNode>> m_targetPatterns;
+ };
+
+ class ObjectPatternNode : public DeconstructionPatternNode {
+ public:
+ static PassRefPtr<ObjectPatternNode> create(VM*);
+ void appendEntry(const JSTokenLocation&, const Identifier& identifier, bool wasString, DeconstructionPatternNode* pattern)
+ {
+ m_targetPatterns.append(Entry(identifier, wasString, pattern));
+ }
+
+ private:
+ ObjectPatternNode(VM*);
+ void collectBoundIdentifiers(Vector<Identifier>&) const;
+ void emitBytecode(BytecodeGenerator&, RegisterID*) const;
+ void toString(StringBuilder&) const;
+ struct Entry {
+ Entry(const Identifier& propertyName, bool wasString, DeconstructionPatternNode* pattern)
+ : propertyName(propertyName)
+ , wasString(wasString)
+ , pattern(pattern)
+ {
+ }
+ Identifier propertyName;
+ bool wasString;
+ RefPtr<DeconstructionPatternNode> pattern;
+ };
+ Vector<Entry> m_targetPatterns;
+ };
+
+ class BindingNode : public DeconstructionPatternNode, ThrowableExpressionData {
+ public:
+ static PassRefPtr<BindingNode> create(VM*, const Identifier& boundProperty, const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end);
+ const Identifier& boundProperty() const { return m_boundProperty; }
+
+ private:
+ BindingNode(VM*, const Identifier& boundProperty, const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end);
+
+ void collectBoundIdentifiers(Vector<Identifier>&) const;
+ void emitBytecode(BytecodeGenerator&, RegisterID*) const;
+ void toString(StringBuilder&) const;
+
+ virtual bool isBindingNode() const { return true; }
+
+ Identifier m_boundProperty;
+ };
+
+ class DeconstructingAssignmentNode : public ExpressionNode, public ParserArenaDeletable {
+ public:
+ DeconstructingAssignmentNode(const JSTokenLocation&, PassRefPtr<DeconstructionPatternNode>, ExpressionNode*);
+ DeconstructionPatternNode* bindings() { return m_bindings.get(); }
+
+ using ParserArenaDeletable::operator new;
+
+ private:
+ virtual bool isLocation() const { return true; }
+ virtual bool isDeconstructionNode() const { return true; }
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ RefPtr<DeconstructionPatternNode> m_bindings;
+ ExpressionNode* m_initializer;
+ };
+
class FuncDeclNode : public StatementNode {
public:
FuncDeclNode(const JSTokenLocation&, const Identifier&, FunctionBodyNode*, const SourceCode&, ParameterNode* = 0);
diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp
index 6b90539..2619834 100644
--- a/Source/JavaScriptCore/parser/Parser.cpp
+++ b/Source/JavaScriptCore/parser/Parser.cpp
@@ -84,7 +84,6 @@
m_token.m_location.startOffset = source.startOffset();
m_token.m_location.endOffset = source.startOffset();
m_token.m_location.lineStartOffset = source.startOffset();
-
m_functionCache = vm->addSourceProviderCache(source.provider());
ScopeRef scope = pushScope();
if (parserMode == JSParseFunctionCode)
@@ -92,8 +91,12 @@
if (strictness == JSParseStrict)
scope->setStrictMode();
if (parameters) {
- for (unsigned i = 0; i < parameters->size(); i++)
- scope->declareParameter(¶meters->at(i));
+ for (unsigned i = 0; i < parameters->size(); i++) {
+ auto parameter = parameters->at(i);
+ if (!parameter->isBindingNode())
+ continue;
+ scope->declareParameter(&static_cast<BindingNode*>(parameter)->boundProperty());
+ }
}
if (!name.isNull())
scope->declareCallee(&name);
@@ -203,7 +206,7 @@
int start = tokenLine();
int end = 0;
int scratch;
- const Identifier* scratch1 = 0;
+ TreeDeconstructionPattern scratch1 = 0;
TreeExpression scratch2 = 0;
JSTextPosition scratch3;
TreeExpression varDecls = parseVarDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3);
@@ -271,43 +274,170 @@
}
template <typename LexerType>
-template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarationList(TreeBuilder& context, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd)
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarationList(TreeBuilder& context, int& declarations, TreeDeconstructionPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd)
{
TreeExpression varDecls = 0;
+ const Identifier* lastIdent;
do {
- declarations++;
+ lastIdent = 0;
+ lastPattern = 0;
JSTokenLocation location(tokenLocation());
next();
- matchOrFail(IDENT);
+ TreeExpression node = 0;
+ declarations++;
+ bool hasInitializer = false;
+ if (match(IDENT)) {
+ JSTextPosition varStart = tokenStartPosition();
+ identStart = varStart;
+ const Identifier* name = m_token.m_data.ident;
+ lastIdent = name;
+ 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);
+ if (hasInitializer) {
+ JSTextPosition varDivot = tokenStartPosition() + 1;
+ initStart = tokenStartPosition();
+ next(TreeBuilder::DontBuildStrings); // consume '='
+ TreeExpression initializer = parseAssignmentExpression(context);
+ initEnd = lastTokenEndPosition();
+ lastInitializer = initializer;
+ failIfFalse(initializer);
+
+ node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEndPosition());
+ }
+ } else {
+ lastIdent = 0;
+ auto pattern = parseDeconstructionPattern<DeconstructToVariables>(context);
+ failIfFalse(pattern);
+ hasInitializer = match(EQUAL);
+ lastPattern = pattern;
+ if (hasInitializer) {
+ next(TreeBuilder::DontBuildStrings); // consume '='
+ TreeExpression rhs = parseExpression(context);
+ node = context.createDeconstructingAssignment(location, pattern, rhs);
+ }
+ ASSERT(node);
+ }
- JSTextPosition varStart = tokenStartPosition();
- identStart = varStart;
- const Identifier* name = m_token.m_data.ident;
- lastIdent = name;
- next();
- bool 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);
if (hasInitializer) {
- JSTextPosition varDivot = tokenStartPosition() + 1;
- initStart = tokenStartPosition();
- next(TreeBuilder::DontBuildStrings); // consume '='
- TreeExpression initializer = parseAssignmentExpression(context);
- initEnd = lastTokenEndPosition();
- lastInitializer = initializer;
- failIfFalse(initializer);
-
- TreeExpression node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEndPosition());
if (!varDecls)
varDecls = node;
else
varDecls = context.combineCommaNodes(location, varDecls, node);
}
} while (match(COMMA));
+ if (lastIdent)
+ lastPattern = createBindingPattern<DeconstructToVariables>(context, *lastIdent, 0);
return varDecls;
}
template <typename LexerType>
+template <DeconstructionKind kind, class TreeBuilder> TreeDeconstructionPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, const Identifier& name, int depth)
+{
+ ASSERT(!name.isEmpty());
+ ASSERT(!name.isNull());
+
+ ASSERT(name.impl()->isIdentifier());
+ if (depth) {
+ if (kind == DeconstructToVariables)
+ failIfFalseIfStrictWithNameAndMessage(declareVariable(&name), "Cannot deconstruct to a variable named", name.impl(), ".");
+ if (kind == DeconstructToParameters) {
+ auto bindingResult = declareBoundParameter(&name);
+ failIfFalseIfStrictWithNameAndMessage(bindingResult != Scope::StrictBindingFailed, "Cannot deconstruct to a parameter named", name.impl(), "in strict mode.");
+ failIfFalseWithNameAndMessage(bindingResult != Scope::BindingFailed, "Cannot deconstruct to a parameter named", name.impl(), ".");
+ }
+ context.addVar(&name, kind == DeconstructToParameters ? 0 : DeclarationStacks::HasInitializer);
+ } else {
+ if (kind == DeconstructToVariables) {
+ failIfFalseIfStrictWithNameAndMessage(declareVariable(&name), "Cannot declare a variable named", name.impl(), "in strict mode.");
+ context.addVar(&name, DeclarationStacks::HasInitializer);
+ }
+
+ if (kind == DeconstructToParameters)
+ failIfFalseIfStrictWithNameAndMessage(declareParameter(&name), "Cannot declare a parameter named", name.impl(), "in strict mode.");
+ }
+ return context.createBindingLocation(m_token.m_location, name, m_token.m_endPosition, m_token.m_startPosition, m_token.m_endPosition);
+}
+
+template <typename LexerType>
+template <DeconstructionKind kind, class TreeBuilder> TreeDeconstructionPattern Parser<LexerType>::parseDeconstructionPattern(TreeBuilder& context, int depth)
+{
+ failIfStackOverflow();
+ int nonLHSCount = m_nonLHSCount;
+ TreeDeconstructionPattern pattern;
+ switch (m_token.m_type) {
+ case OPENBRACKET: {
+ auto arrayPattern = context.createArrayPattern(m_token.m_location);
+ next();
+ do {
+ while (match(COMMA)) {
+ context.appendArrayPatternSkipEntry(arrayPattern, m_token.m_location);
+ next();
+ }
+ failIfTrue(hasError());
+ JSTokenLocation location = m_token.m_location;
+ auto innerPattern = parseDeconstructionPattern<kind>(context, depth + 1);
+ failIfFalse(innerPattern);
+ context.appendArrayPatternEntry(arrayPattern, location, innerPattern);
+ } while (consume(COMMA));
+ consumeOrFail(CLOSEBRACKET);
+ pattern = arrayPattern;
+ break;
+ }
+ case OPENBRACE: {
+ next();
+ auto objectPattern = context.createObjectPattern(m_token.m_location);
+ bool wasString = false;
+ do {
+ Identifier propertyName;
+ TreeDeconstructionPattern innerPattern = 0;
+ JSTokenLocation location = m_token.m_location;
+ if (match(IDENT)) {
+ propertyName = *m_token.m_data.ident;
+ next();
+ if (consume(COLON))
+ innerPattern = parseDeconstructionPattern<kind>(context, depth + 1);
+ else
+ innerPattern = createBindingPattern<kind>(context, propertyName, depth);
+ } else {
+ switch (m_token.m_type) {
+ case NUMBER:
+ propertyName = Identifier::from(m_vm, m_token.m_data.doubleValue);
+ break;
+ case STRING:
+ propertyName = *m_token.m_data.ident;
+ wasString = true;
+ break;
+ default:
+ failIfTrue(!(m_token.m_type & KeywordTokenFlag));
+ propertyName = *m_token.m_data.ident;
+ break;
+ }
+ next();
+ consumeOrFail(COLON);
+ innerPattern = parseDeconstructionPattern<kind>(context, depth + 1);
+ }
+ failIfFalse(innerPattern);
+ context.appendObjectPatternEntry(objectPattern, location, wasString, propertyName, innerPattern);
+ } while (consume(COMMA));
+ consumeOrFail(CLOSEBRACE);
+ pattern = objectPattern;
+ break;
+ }
+
+ default: {
+ matchOrFail(IDENT);
+ pattern = createBindingPattern<kind>(context, *m_token.m_data.ident, depth);
+ next();
+ break;
+ }
+ }
+ m_nonLHSCount = nonLHSCount;
+ return pattern;
+}
+
+template <typename LexerType>
template <class TreeBuilder> TreeConstDeclList Parser<LexerType>::parseConstDeclarationList(TreeBuilder& context)
{
failIfTrue(strictMode());
@@ -351,10 +481,9 @@
if (match(VAR)) {
/*
for (var IDENT in expression) statement
- for (var IDENT = expression in expression) statement
for (var varDeclarationList; expressionOpt; expressionOpt)
*/
- const Identifier* forInTarget = 0;
+ TreeDeconstructionPattern forInTarget = 0;
TreeExpression forInInitializer = 0;
m_allowsIn = false;
JSTextPosition initStart;
@@ -369,7 +498,7 @@
failIfFalse(declarations == 1);
failIfTrueWithMessage(forInInitializer, "Cannot use initialiser syntax in a for-in loop");
-
+
// Handle for-in with var declaration
JSTextPosition inLocation = tokenStartPosition();
consumeOrFail(INTOKEN);
@@ -386,7 +515,6 @@
TreeStatement statement = parseStatement(context, unused);
endLoop();
failIfFalse(statement);
-
return context.createForInLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine);
}
@@ -772,18 +900,14 @@
template <typename LexerType>
template <class TreeBuilder> TreeFormalParameterList Parser<LexerType>::parseFormalParameters(TreeBuilder& context)
{
- matchOrFail(IDENT);
- failIfFalseIfStrictWithNameAndMessage(declareParameter(m_token.m_data.ident), "Cannot declare a parameter named", m_token.m_data.ident->impl(), " in strict mode");
- TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident);
+ auto parameter = parseDeconstructionPattern<DeconstructToParameters>(context);
+ failIfFalse(parameter);
+ TreeFormalParameterList list = context.createFormalParameterList(parameter);
TreeFormalParameterList tail = list;
- next();
- while (match(COMMA)) {
- next();
- matchOrFail(IDENT);
- const Identifier* ident = m_token.m_data.ident;
- failIfFalseIfStrictWithNameAndMessage(declareParameter(ident), "Cannot declare a parameter named", ident->impl(), "in strict mode");
- next();
- tail = context.createFormalParameterList(tail, *ident);
+ while (consume(COMMA)) {
+ parameter = parseDeconstructionPattern<DeconstructToParameters>(context);
+ failIfFalse(parameter);
+ tail = context.createFormalParameterList(tail, parameter);
}
return list;
}
@@ -1155,7 +1279,7 @@
declareWrite(m_lastIdentifier);
m_lastIdentifier = 0;
}
- lhs = parseConditionalExpression(context);
+ lhs = parseAssignmentExpression(context);
failIfFalse(lhs);
if (initialNonLHSCount != m_nonLHSCount)
break;
diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h
index d72ae17..818948b 100644
--- a/Source/JavaScriptCore/parser/Parser.h
+++ b/Source/JavaScriptCore/parser/Parser.h
@@ -73,6 +73,7 @@
#define TreeFunctionBody typename TreeBuilder::FunctionBody
#define TreeProperty typename TreeBuilder::Property
#define TreePropertyList typename TreeBuilder::PropertyList
+#define TreeDeconstructionPattern typename TreeBuilder::DeconstructionPattern
COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens);
@@ -228,6 +229,26 @@
m_shadowsArguments = true;
return isValidStrictMode;
}
+
+ enum BindingResult {
+ BindingFailed,
+ StrictBindingFailed,
+ BindingSucceeded
+ };
+ BindingResult declareBoundParameter(const Identifier* ident)
+ {
+ bool isArguments = m_vm->propertyNames->arguments == *ident;
+ bool newEntry = m_declaredVariables.add(ident->string().impl()).isNewEntry;
+ bool isValidStrictMode = newEntry && m_vm->propertyNames->eval != *ident && !isArguments;
+ m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+
+ if (isArguments)
+ m_shadowsArguments = true;
+ if (!newEntry)
+ return BindingFailed;
+ return isValidStrictMode ? BindingSucceeded : StrictBindingFailed;
+ }
+
void useVariable(const Identifier* ident, bool isEval)
{
@@ -861,6 +882,7 @@
bool strictMode() { return currentScope()->strictMode(); }
bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
+ Scope::BindingResult declareBoundParameter(const Identifier* ident) { return currentScope()->declareBoundParameter(ident); }
bool breakIsValid()
{
ScopeRef current = currentScope();
@@ -931,8 +953,11 @@
template <bool strict, class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&);
template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&);
template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&);
- template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd);
- template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, TreeDeconstructionPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd);
+ template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder&);
+
+ template <DeconstructionKind, class TreeBuilder> ALWAYS_INLINE TreeDeconstructionPattern createBindingPattern(TreeBuilder&, const Identifier&, int depth);
+ template <DeconstructionKind, class TreeBuilder> TreeDeconstructionPattern parseDeconstructionPattern(TreeBuilder&, int depth = 0);
template <FunctionRequirements, 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();
diff --git a/Source/JavaScriptCore/parser/SyntaxChecker.h b/Source/JavaScriptCore/parser/SyntaxChecker.h
index 9929caf..965ff0d 100644
--- a/Source/JavaScriptCore/parser/SyntaxChecker.h
+++ b/Source/JavaScriptCore/parser/SyntaxChecker.h
@@ -111,7 +111,10 @@
typedef int Clause;
typedef int ConstDeclList;
typedef int BinaryOperand;
-
+ typedef int DeconstructionPattern;
+ typedef int ArrayPattern;
+ typedef int ObjectPattern;
+
static const bool CreatesAST = false;
static const bool NeedsFreeVariableInfo = false;
static const bool CanUseFunctionCache = true;
@@ -173,8 +176,8 @@
int createPropertyList(const JSTokenLocation&, Property, int) { return 1; }
int createElementList(int, int) { return 1; }
int createElementList(int, int, int) { return 1; }
- int createFormalParameterList(const Identifier&) { return 1; }
- int createFormalParameterList(int, const Identifier&) { return 1; }
+ int createFormalParameterList(DeconstructionPattern) { return 1; }
+ int createFormalParameterList(int, DeconstructionPattern) { return 1; }
int createClause(int, int) { return 1; }
int createClauseList(int) { return 1; }
int createClauseList(int, int) { return 1; }
@@ -185,7 +188,6 @@
int createIfStatement(const JSTokenLocation&, int, int, int, int) { return 1; }
int createIfStatement(const JSTokenLocation&, int, int, int, int, int) { return 1; }
int createForLoop(const JSTokenLocation&, int, int, int, int, int, int) { return 1; }
- int createForInLoop(const JSTokenLocation&, const Identifier*, int, int, int, int, int, int, int) { return 1; }
int createForInLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int) { return 1; }
int createEmptyStatement(const JSTokenLocation&) { return 1; }
int createVarStatement(const JSTokenLocation&, int, int, int) { return 1; }
@@ -250,7 +252,32 @@
const Identifier& getName(const Property& property) const { ASSERT(property.name); return *property.name; }
PropertyNode::Type getType(const Property& property) const { return property.type; }
bool isResolve(ExpressionType expr) const { return expr == ResolveExpr || expr == ResolveEvalExpr; }
+ ExpressionType createDeconstructingAssignment(const JSTokenLocation&, int, ExpressionType)
+ {
+ return 1;
+ }
+ ArrayPattern createArrayPattern(const JSTokenLocation&)
+ {
+ return 1;
+ }
+ void appendArrayPatternSkipEntry(ArrayPattern, const JSTokenLocation&)
+ {
+ }
+ void appendArrayPatternEntry(ArrayPattern, const JSTokenLocation&, DeconstructionPattern)
+ {
+ }
+ ObjectPattern createObjectPattern(const JSTokenLocation&)
+ {
+ return 1;
+ }
+ void appendObjectPatternEntry(ArrayPattern, const JSTokenLocation&, bool, const Identifier&, DeconstructionPattern)
+ {
+ }
+ DeconstructionPattern createBindingLocation(const JSTokenLocation&, const Identifier&, const JSTextPosition&, const JSTextPosition&, const JSTextPosition&)
+ {
+ return 1;
+ }
private:
int m_topBinaryExpr;
int m_topUnaryToken;
diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp
index 1e14f3a..4f00d1f 100644
--- a/Source/JavaScriptCore/runtime/JSONObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSONObject.cpp
@@ -302,7 +302,15 @@
}
}
}
-
+
+void escapeStringToBuilder(StringBuilder& builder, const String& message)
+{
+ if (message.is8Bit())
+ appendStringToStringBuilder(builder, message.characters8(), message.length());
+ else
+ appendStringToStringBuilder(builder, message.characters16(), message.length());
+}
+
void Stringifier::appendQuotedString(StringBuilder& builder, const String& value)
{
int length = value.length();
diff --git a/Source/JavaScriptCore/runtime/JSONObject.h b/Source/JavaScriptCore/runtime/JSONObject.h
index 59f19c1..732fe4d 100644
--- a/Source/JavaScriptCore/runtime/JSONObject.h
+++ b/Source/JavaScriptCore/runtime/JSONObject.h
@@ -63,6 +63,8 @@
JS_EXPORT_PRIVATE JSValue JSONParse(ExecState*, const String&);
String JSONStringify(ExecState*, JSValue, unsigned indent);
+ void escapeStringToBuilder(StringBuilder&, const String&);
+
} // namespace JSC
#endif // JSONObject_h