[ES6] Catch parameter should accept BindingPattern
https://bugs.webkit.org/show_bug.cgi?id=152385

Reviewed by Saam Barati.

Source/JavaScriptCore:

This patch implements destructuring in catch parameter.
Catch parameter accepts binding pattern and binding identifier.
It creates lexical bindings. And "yield" and "let" are specially
handled as is the same to function parameters.

In addition to that, we make destructuring parsing errors more descriptive.

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitPushCatchScope):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::TryNode::emitBytecode):
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createTryStatement):
* parser/NodeConstructors.h:
(JSC::TryNode::TryNode):
* parser/Nodes.h:
* parser/Parser.cpp:
(JSC::Parser<LexerType>::createBindingPattern):
(JSC::Parser<LexerType>::tryParseDestructuringPatternExpression):
(JSC::Parser<LexerType>::parseBindingOrAssignmentElement):
(JSC::destructuringKindToVariableKindName):
(JSC::Parser<LexerType>::parseDestructuringPattern):
(JSC::Parser<LexerType>::parseTryStatement):
(JSC::Parser<LexerType>::parseFormalParameters):
(JSC::Parser<LexerType>::parseFunctionParameters):
* parser/Parser.h:
(JSC::Parser::destructuringKindFromDeclarationType):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createTryStatement):
* tests/es6.yaml:
* tests/es6/destructuring_in_catch_heads.js: Added.
(test):
* tests/stress/catch-parameter-destructuring.js: Added.
(shouldBe):
(shouldThrow):
(prototype.call):
(catch):
(shouldThrow.try.throw.get error):
(initialize):
(array):
(generator.gen):
(generator):
* tests/stress/catch-parameter-syntax.js: Added.
(testSyntax):
(testSyntaxError):
* tests/stress/reserved-word-with-escape.js:
(testSyntaxError.String.raw.a):
(String.raw.SyntaxError.Cannot.use.the.keyword.string_appeared_here.as.a.name):
* tests/stress/yield-named-variable.js:

LayoutTests:

* js/dom/reserved-words-as-property-expected.txt:
* js/let-syntax-expected.txt:
* js/mozilla/strict/12.14.1-expected.txt:
* js/mozilla/strict/script-tests/12.14.1.js:
* sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T10-expected.txt:
* sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T13-expected.txt:
* sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T5-expected.txt:
* sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T7-expected.txt:
* sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T8-expected.txt:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@195439 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 602389f..e623013 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,61 @@
+2016-01-21  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [ES6] Catch parameter should accept BindingPattern
+        https://bugs.webkit.org/show_bug.cgi?id=152385
+
+        Reviewed by Saam Barati.
+
+        This patch implements destructuring in catch parameter.
+        Catch parameter accepts binding pattern and binding identifier.
+        It creates lexical bindings. And "yield" and "let" are specially
+        handled as is the same to function parameters.
+
+        In addition to that, we make destructuring parsing errors more descriptive.
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitPushCatchScope):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::TryNode::emitBytecode):
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::createTryStatement):
+        * parser/NodeConstructors.h:
+        (JSC::TryNode::TryNode):
+        * parser/Nodes.h:
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::createBindingPattern):
+        (JSC::Parser<LexerType>::tryParseDestructuringPatternExpression):
+        (JSC::Parser<LexerType>::parseBindingOrAssignmentElement):
+        (JSC::destructuringKindToVariableKindName):
+        (JSC::Parser<LexerType>::parseDestructuringPattern):
+        (JSC::Parser<LexerType>::parseTryStatement):
+        (JSC::Parser<LexerType>::parseFormalParameters):
+        (JSC::Parser<LexerType>::parseFunctionParameters):
+        * parser/Parser.h:
+        (JSC::Parser::destructuringKindFromDeclarationType):
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::createTryStatement):
+        * tests/es6.yaml:
+        * tests/es6/destructuring_in_catch_heads.js: Added.
+        (test):
+        * tests/stress/catch-parameter-destructuring.js: Added.
+        (shouldBe):
+        (shouldThrow):
+        (prototype.call):
+        (catch):
+        (shouldThrow.try.throw.get error):
+        (initialize):
+        (array):
+        (generator.gen):
+        (generator):
+        * tests/stress/catch-parameter-syntax.js: Added.
+        (testSyntax):
+        (testSyntaxError):
+        * tests/stress/reserved-word-with-escape.js:
+        (testSyntaxError.String.raw.a):
+        (String.raw.SyntaxError.Cannot.use.the.keyword.string_appeared_here.as.a.name):
+        * tests/stress/yield-named-variable.js:
+
 2016-01-21  Filip Pizlo  <fpizlo@apple.com>
 
         Unreviewed, fix build.
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index d15e224..f889985 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -3588,14 +3588,9 @@
     m_localScopeDepth--;
 }
 
-void BytecodeGenerator::emitPushCatchScope(const Identifier& property, RegisterID* exceptionValue, VariableEnvironment& environment)
+void BytecodeGenerator::emitPushCatchScope(VariableEnvironment& environment)
 {
-    RELEASE_ASSERT(environment.contains(property.impl()));
     pushLexicalScopeInternal(environment, TDZCheckOptimization::Optimize, NestedScopeType::IsNotNested, nullptr, TDZRequirement::NotUnderTDZ, ScopeType::CatchScope, ScopeRegisterType::Block);
-    Variable exceptionVar = variable(property);
-    RELEASE_ASSERT(exceptionVar.isResolved());
-    RefPtr<RegisterID> scope = emitResolveScope(nullptr, exceptionVar);
-    emitPutToScope(scope.get(), exceptionVar, exceptionValue, ThrowIfNotFound, NotInitialization);
 }
 
 void BytecodeGenerator::emitPopCatchScope(VariableEnvironment& environment) 
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 7d0c20b..5e3845b 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -639,7 +639,7 @@
         void emitThrowReferenceError(const String& message);
         void emitThrowTypeError(const String& message);
 
-        void emitPushCatchScope(const Identifier& property, RegisterID* exceptionValue, VariableEnvironment&);
+        void emitPushCatchScope(VariableEnvironment&);
         void emitPopCatchScope(VariableEnvironment&);
 
         void emitGetScope();
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 3c4f20b..a390371 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -2927,7 +2927,8 @@
             tryData = generator.pushTry(here.get());
         }
 
-        generator.emitPushCatchScope(m_thrownValueIdent, thrownValueRegister.get(), m_lexicalVariables);
+        generator.emitPushCatchScope(m_lexicalVariables);
+        m_catchPattern->bindValue(generator, thrownValueRegister.get());
         generator.emitProfileControlFlow(m_tryBlock->endOffset() + 1);
         if (m_finallyBlock)
             generator.emitNode(dst, m_catchBlock);
diff --git a/Source/JavaScriptCore/parser/ASTBuilder.h b/Source/JavaScriptCore/parser/ASTBuilder.h
index 4331942..104989d 100644
--- a/Source/JavaScriptCore/parser/ASTBuilder.h
+++ b/Source/JavaScriptCore/parser/ASTBuilder.h
@@ -591,9 +591,9 @@
         return result;
     }
 
-    StatementNode* createTryStatement(const JSTokenLocation& location, StatementNode* tryBlock, const Identifier* ident, StatementNode* catchBlock, StatementNode* finallyBlock, int startLine, int endLine, VariableEnvironment& catchEnvironment)
+    StatementNode* createTryStatement(const JSTokenLocation& location, StatementNode* tryBlock, DestructuringPatternNode* catchPattern, StatementNode* catchBlock, StatementNode* finallyBlock, int startLine, int endLine, VariableEnvironment& catchEnvironment)
     {
-        TryNode* result = new (m_parserArena) TryNode(location, tryBlock, *ident, catchBlock, catchEnvironment, finallyBlock);
+        TryNode* result = new (m_parserArena) TryNode(location, tryBlock, catchPattern, catchBlock, catchEnvironment, finallyBlock);
         result->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
         return result;
     }
diff --git a/Source/JavaScriptCore/parser/NodeConstructors.h b/Source/JavaScriptCore/parser/NodeConstructors.h
index 2ab5370..38d6266 100644
--- a/Source/JavaScriptCore/parser/NodeConstructors.h
+++ b/Source/JavaScriptCore/parser/NodeConstructors.h
@@ -874,11 +874,11 @@
     {
     }
 
-    inline TryNode::TryNode(const JSTokenLocation& location, StatementNode* tryBlock, const Identifier& thrownValueIdent, StatementNode* catchBlock, VariableEnvironment& catchEnvironment, StatementNode* finallyBlock)
+    inline TryNode::TryNode(const JSTokenLocation& location, StatementNode* tryBlock, DestructuringPatternNode* catchPattern, StatementNode* catchBlock, VariableEnvironment& catchEnvironment, StatementNode* finallyBlock)
         : StatementNode(location)
         , VariableEnvironmentNode(catchEnvironment)
         , m_tryBlock(tryBlock)
-        , m_thrownValueIdent(thrownValueIdent)
+        , m_catchPattern(catchPattern)
         , m_catchBlock(catchBlock)
         , m_finallyBlock(finallyBlock)
     {
diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h
index 9a9345a..ebad68d 100644
--- a/Source/JavaScriptCore/parser/Nodes.h
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -1526,13 +1526,13 @@
     public:
         using ParserArenaDeletable::operator new;
 
-        TryNode(const JSTokenLocation&, StatementNode* tryBlock, const Identifier& exceptionIdent, StatementNode* catchBlock, VariableEnvironment& catchEnvironment, StatementNode* finallyBlock);
+        TryNode(const JSTokenLocation&, StatementNode* tryBlock, DestructuringPatternNode* catchPattern, StatementNode* catchBlock, VariableEnvironment& catchEnvironment, StatementNode* finallyBlock);
 
     private:
         virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
 
         StatementNode* m_tryBlock;
-        const Identifier& m_thrownValueIdent;
+        DestructuringPatternNode* m_catchPattern;
         StatementNode* m_catchBlock;
         StatementNode* m_finallyBlock;
     };
diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp
index e00d800..56e3ff9 100644
--- a/Source/JavaScriptCore/parser/Parser.cpp
+++ b/Source/JavaScriptCore/parser/Parser.cpp
@@ -795,20 +795,35 @@
     
     ASSERT(name.impl()->isAtomic() || name.impl()->isSymbol());
 
-    if (kind == DestructureToVariables) {
+    switch (kind) {
+    case DestructuringKind::DestructureToVariables: {
         DeclarationResultMask declarationResult = declareVariable(&name);
         failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot declare a variable named '", name.impl(), "' in strict mode");
         if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration)
             internalFailWithMessage(false, "Cannot declare a var variable that shadows a let/const/class variable: '", name.impl(), "'");
-    } else if (kind == DestructureToLet || kind == DestructureToConst) {
-        DeclarationResultMask declarationResult = declareVariable(&name, kind == DestructureToLet ? DeclarationType::LetDeclaration : DeclarationType::ConstDeclaration);
+        break;
+    }
+
+    case DestructuringKind::DestructureToLet:
+    case DestructuringKind::DestructureToConst:
+    case DestructuringKind::DestructureToCatchParameters: {
+        DeclarationResultMask declarationResult = declareVariable(&name, kind == DestructuringKind::DestructureToConst ? DeclarationType::ConstDeclaration : DeclarationType::LetDeclaration);
         if (declarationResult != DeclarationResult::Valid) {
             failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot destructure to a variable named '", name.impl(), "' in strict mode");
             failIfTrue(declarationResult & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare a lexical variable twice: '", name.impl(), "'");
         }
-    } else if (kind == DestructureToParameters) {
+        break;
+    }
+
+    case DestructuringKind::DestructureToParameters: {
         declareRestOrNormalParameter(name, duplicateIdentifier);
         propagateError();
+        break;
+    }
+
+    case DestructuringKind::DestructureToExpressions: {
+        break;
+    }
     }
 
     if (exportType == ExportType::Exported) {
@@ -856,13 +871,13 @@
 template <typename LexerType>
 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::tryParseDestructuringPatternExpression(TreeBuilder& context, AssignmentContext bindingContext)
 {
-    return parseDestructuringPattern(context, DestructureToExpressions, ExportType::NotExported, nullptr, nullptr, bindingContext);
+    return parseDestructuringPattern(context, DestructuringKind::DestructureToExpressions, ExportType::NotExported, nullptr, nullptr, bindingContext);
 }
 
 template <typename LexerType>
 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseBindingOrAssignmentElement(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
 {
-    if (kind == DestructureToExpressions)
+    if (kind == DestructuringKind::DestructureToExpressions)
         return parseAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
     return parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
 }
@@ -893,6 +908,25 @@
     return createAssignmentElement(context, element, startPosition, lastTokenEndPosition());
 }
 
+static const char* destructuringKindToVariableKindName(DestructuringKind kind)
+{
+    switch (kind) {
+    case DestructuringKind::DestructureToLet:
+    case DestructuringKind::DestructureToConst:
+        return "lexical variable name";
+    case DestructuringKind::DestructureToVariables:
+        return "variable name";
+    case DestructuringKind::DestructureToParameters:
+        return "parameter name";
+    case DestructuringKind::DestructureToCatchParameters:
+        return "catch parameter name";
+    case DestructuringKind::DestructureToExpressions:
+        return "expression name";
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+    return "invalid";
+}
+
 template <typename LexerType>
 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDestructuringPattern(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
 {
@@ -924,11 +958,11 @@
                 JSTokenLocation location = m_token.m_location;
                 next();
                 auto innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
-                if (kind == DestructureToExpressions && !innerPattern)
+                if (kind == DestructuringKind::DestructureToExpressions && !innerPattern)
                     return 0;
                 failIfFalse(innerPattern, "Cannot parse this destructuring pattern");
 
-                failIfTrue(kind != DestructureToExpressions && !context.isBindingNode(innerPattern),  "Expected identifier for a rest element destructuring pattern");
+                failIfTrue(kind != DestructuringKind::DestructureToExpressions && !context.isBindingNode(innerPattern),  "Expected identifier for a rest element destructuring pattern");
 
                 context.appendArrayPatternRestEntry(arrayPattern, location, innerPattern);
                 restElementWasFound = true;
@@ -937,7 +971,7 @@
 
             JSTokenLocation location = m_token.m_location;
             auto innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
-            if (kind == DestructureToExpressions && !innerPattern)
+            if (kind == DestructuringKind::DestructureToExpressions && !innerPattern)
                 return 0;
             failIfFalse(innerPattern, "Cannot parse this destructuring pattern");
             TreeExpression defaultValue = parseDefaultValueForDestructuringPattern(context);
@@ -967,14 +1001,14 @@
             TreeDestructuringPattern innerPattern = 0;
             JSTokenLocation location = m_token.m_location;
             if (matchSpecIdentifier()) {
-                failIfTrue(match(LET) && (kind == DestructureToLet || kind == DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
+                failIfTrue(match(LET) && (kind == DestructuringKind::DestructureToLet || kind == DestructuringKind::DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
                 propertyName = m_token.m_data.ident;
                 JSToken identifierToken = m_token;
                 next();
                 if (consume(COLON))
                     innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
                 else {
-                    if (kind == DestructureToExpressions) {
+                    if (kind == DestructuringKind::DestructureToExpressions) {
                         bool isEvalOrArguments = m_vm->propertyNames->eval == *propertyName || m_vm->propertyNames->arguments == *propertyName;
                         if (isEvalOrArguments && strictMode())
                             reclassifyExpressionError(ErrorIndicatesPattern, ErrorIndicatesNothing);
@@ -1001,7 +1035,7 @@
                     break;
                 default:
                     if (m_token.m_type != RESERVED && m_token.m_type != RESERVED_IF_STRICT && !(m_token.m_type & KeywordTokenFlag)) {
-                        if (kind == DestructureToExpressions)
+                        if (kind == DestructuringKind::DestructureToExpressions)
                             return 0;
                         failWithMessage("Expected a property name");
                     }
@@ -1010,7 +1044,7 @@
                 }
                 next();
                 if (!consume(COLON)) {
-                    if (kind == DestructureToExpressions)
+                    if (kind == DestructuringKind::DestructureToExpressions)
                         return 0;
                     semanticFailIfTrue(tokenType == RESERVED, "Cannot use abbreviated destructuring syntax for reserved name '", propertyName->impl(), "'");
                     semanticFailIfTrue(tokenType == RESERVED_IF_STRICT, "Cannot use abbreviated destructuring syntax for reserved name '", propertyName->impl(), "' in strict mode");
@@ -1020,7 +1054,7 @@
                 }
                 innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
             }
-            if (kind == DestructureToExpressions && !innerPattern)
+            if (kind == DestructuringKind::DestructureToExpressions && !innerPattern)
                 return 0;
             failIfFalse(innerPattern, "Cannot parse this destructuring pattern");
             TreeExpression defaultValue = parseDefaultValueForDestructuringPattern(context);
@@ -1032,7 +1066,7 @@
             }
         } while (consume(COMMA));
 
-        if (kind == DestructureToExpressions && !match(CLOSEBRACE))
+        if (kind == DestructuringKind::DestructureToExpressions && !match(CLOSEBRACE))
             return 0;
         consumeOrFail(CLOSEBRACE, "Expected either a closing '}' or an ',' after a property destructuring pattern");
         pattern = objectPattern;
@@ -1041,12 +1075,12 @@
 
     default: {
         if (!matchSpecIdentifier()) {
-            if (kind == DestructureToExpressions)
+            if (kind == DestructuringKind::DestructureToExpressions)
                 return 0;
-            semanticFailureDueToKeyword("variable name");
+            semanticFailureDueToKeyword(destructuringKindToVariableKindName(kind));
             failWithMessage("Expected a parameter pattern or a ')' in parameter list");
         }
-        failIfTrue(match(LET) && (kind == DestructureToLet || kind == DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
+        failIfTrue(match(LET) && (kind == DestructuringKind::DestructureToLet || kind == DestructuringKind::DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
         pattern = createBindingPattern(context, kind, exportType, *m_token.m_data.ident, m_token, bindingContext, duplicateIdentifier);
         next();
         break;
@@ -1466,7 +1500,7 @@
     ASSERT(match(TRY));
     JSTokenLocation location(tokenLocation());
     TreeStatement tryBlock = 0;
-    const Identifier* ident = &m_vm->propertyNames->nullIdentifier;
+    TreeDestructuringPattern catchPattern = 0;
     TreeStatement catchBlock = 0;
     TreeStatement finallyBlock = 0;
     int firstLine = tokenLine();
@@ -1481,22 +1515,25 @@
         next();
         
         handleProductionOrFail(OPENPAREN, "(", "start", "'catch' target");
-        if (!matchSpecIdentifier()) {
-            semanticFailureDueToKeyword("catch variable name");
-            failWithMessage("Expected identifier name as catch target");
-        }
-        ident = m_token.m_data.ident;
-        next();
         AutoPopScopeRef catchScope(this, pushScope());
         catchScope->setIsLexicalScope();
         catchScope->preventVarDeclarations();
-        failIfTrueIfStrict(catchScope->declareLexicalVariable(ident, false) & DeclarationResult::InvalidStrictMode, "Cannot declare a catch variable named '", ident->impl(), "' in strict mode");
+        const Identifier* ident = nullptr;
+        if (matchSpecIdentifier()) {
+            ident = m_token.m_data.ident;
+            catchPattern = context.createBindingLocation(m_token.m_location, *ident, m_token.m_startPosition, m_token.m_endPosition, AssignmentContext::DeclarationStatement);
+            next();
+            failIfTrueIfStrict(catchScope->declareLexicalVariable(ident, false) & DeclarationResult::InvalidStrictMode, "Cannot declare a catch variable named '", ident->impl(), "' in strict mode");
+        } else {
+            catchPattern = parseDestructuringPattern(context, DestructuringKind::DestructureToCatchParameters, ExportType::NotExported);
+            failIfFalse(catchPattern, "Cannot parse this destructuring pattern");
+        }
         handleProductionOrFail(CLOSEPAREN, ")", "end", "'catch' target");
         matchOrFail(OPENBRACE, "Expected exception handler to be a block statement");
         catchBlock = parseBlockStatement(context);
         failIfFalse(catchBlock, "Unable to parse 'catch' block");
         catchEnvironment = catchScope->finalizeLexicalEnvironment();
-        RELEASE_ASSERT(catchEnvironment.size() == 1 && catchEnvironment.contains(ident->impl()));
+        RELEASE_ASSERT(!ident || (catchEnvironment.size() == 1 && catchEnvironment.contains(ident->impl())));
         popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo);
     }
     
@@ -1507,7 +1544,7 @@
         failIfFalse(finallyBlock, "Cannot parse finally body");
     }
     failIfFalse(catchBlock || finallyBlock, "Try statements must have at least a catch or finally block");
-    return context.createTryStatement(location, tryBlock, ident, catchBlock, finallyBlock, firstLine, lastLine, catchEnvironment);
+    return context.createTryStatement(location, tryBlock, catchPattern, catchBlock, finallyBlock, firstLine, lastLine, catchEnvironment);
 }
 
 template <typename LexerType>
@@ -1691,7 +1728,7 @@
             failIfTrue(match(COMMA), "Rest parameter should be the last parameter in a function declaration"); // Let's have a good error message for this common case.
             isRestParameter = true;
         } else
-            parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter, &hasDestructuringPattern);
+            parameter = parseDestructuringPattern(context, DestructuringKind::DestructureToParameters, ExportType::NotExported, &duplicateParameter, &hasDestructuringPattern);
         failIfFalse(parameter, "Cannot parse parameter pattern");
         if (!isRestParameter)
             defaultValue = parseDefaultValueForDestructuringPattern(context);
@@ -1783,7 +1820,7 @@
                 consumeOrFail(CLOSEPAREN, "Expected a ')' or a ',' after a parameter declaration");
             } else {
                 functionInfo.parameterCount = 1;
-                auto parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported);
+                auto parameter = parseDestructuringPattern(context, DestructuringKind::DestructureToParameters, ExportType::NotExported);
                 failIfFalse(parameter, "Cannot parse parameter pattern");
                 context.appendParameter(parameterList, parameter, 0);
             }
@@ -1803,7 +1840,7 @@
     } else if (mode == SourceParseMode::SetterMode) {
         failIfTrue(match(CLOSEPAREN), "setter functions must have one parameter");
         const Identifier* duplicateParameter = nullptr;
-        auto parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter);
+        auto parameter = parseDestructuringPattern(context, DestructuringKind::DestructureToParameters, ExportType::NotExported, &duplicateParameter);
         failIfFalse(parameter, "setter functions must have one parameter");
         auto defaultValue = parseDefaultValueForDestructuringPattern(context);
         propagateError();
diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h
index 329edbe..3050c55 100644
--- a/Source/JavaScriptCore/parser/Parser.h
+++ b/Source/JavaScriptCore/parser/Parser.h
@@ -81,10 +81,11 @@
 enum FunctionBodyType { ArrowFunctionBodyExpression, ArrowFunctionBodyBlock, StandardFunctionBodyBlock };
 enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
 
-enum DestructuringKind {
+enum class DestructuringKind {
     DestructureToVariables,
     DestructureToLet,
     DestructureToConst,
+    DestructureToCatchParameters,
     DestructureToParameters,
     DestructureToExpressions
 };
@@ -801,15 +802,15 @@
     {
         switch (type) {
         case DeclarationType::VarDeclaration:
-            return DestructureToVariables;
+            return DestructuringKind::DestructureToVariables;
         case DeclarationType::LetDeclaration:
-            return DestructureToLet;
+            return DestructuringKind::DestructureToLet;
         case DeclarationType::ConstDeclaration:
-            return DestructureToConst;
+            return DestructuringKind::DestructureToConst;
         }
 
         RELEASE_ASSERT_NOT_REACHED();
-        return DestructureToVariables;
+        return DestructuringKind::DestructureToVariables;
     }
 
     ALWAYS_INLINE AssignmentContext assignmentContextFromDeclarationType(DeclarationType type)
diff --git a/Source/JavaScriptCore/parser/SyntaxChecker.h b/Source/JavaScriptCore/parser/SyntaxChecker.h
index 2c77285..91480bb 100644
--- a/Source/JavaScriptCore/parser/SyntaxChecker.h
+++ b/Source/JavaScriptCore/parser/SyntaxChecker.h
@@ -243,7 +243,7 @@
     int createBreakStatement(const JSTokenLocation&, const Identifier*, int, int) { return StatementResult; }
     int createContinueStatement(const JSTokenLocation&, int, int) { return StatementResult; }
     int createContinueStatement(const JSTokenLocation&, const Identifier*, int, int) { return StatementResult; }
-    int createTryStatement(const JSTokenLocation&, int, const Identifier*, int, int, int, int, VariableEnvironment&) { return StatementResult; }
+    int createTryStatement(const JSTokenLocation&, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
     int createSwitchStatement(const JSTokenLocation&, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
     int createWhileStatement(const JSTokenLocation&, int, int, int, int) { return StatementResult; }
     int createWithStatement(const JSTokenLocation&, int, int, int, int, int, int) { return StatementResult; }
diff --git a/Source/JavaScriptCore/tests/es6.yaml b/Source/JavaScriptCore/tests/es6.yaml
index f9ab3a1..fcc24ef 100644
--- a/Source/JavaScriptCore/tests/es6.yaml
+++ b/Source/JavaScriptCore/tests/es6.yaml
@@ -172,6 +172,8 @@
   cmd: runES6 :normal
 - path: es6/destructuring_empty_patterns_in_parameters.js
   cmd: runES6 :normal
+- path: es6/destructuring_in_catch_heads.js
+  cmd: runES6 :normal
 - path: es6/destructuring_in_for-in_loop_heads.js
   cmd: runES6 :normal
 - path: es6/destructuring_in_for-of_loop_heads.js
diff --git a/Source/JavaScriptCore/tests/es6/destructuring_in_catch_heads.js b/Source/JavaScriptCore/tests/es6/destructuring_in_catch_heads.js
new file mode 100644
index 0000000..6468ed7
--- /dev/null
+++ b/Source/JavaScriptCore/tests/es6/destructuring_in_catch_heads.js
@@ -0,0 +1,17 @@
+function test() {
+
+try {
+  throw [1,2];
+} catch([i,j]) {
+  try {
+    throw { k: 3, l: 4 };
+  } catch({k, l}) {
+    return i === 1 && j === 2 && k === 3 && l === 4;
+  }
+}
+
+}
+
+if (!test())
+    throw new Error("Test failed");
+
diff --git a/Source/JavaScriptCore/tests/stress/catch-parameter-destructuring.js b/Source/JavaScriptCore/tests/stress/catch-parameter-destructuring.js
new file mode 100644
index 0000000..50d225e
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/catch-parameter-destructuring.js
@@ -0,0 +1,146 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+class CallGuard {
+    constructor()
+    {
+        this.called = false;
+    }
+
+    call()
+    {
+        this.called = true;
+    }
+}
+
+(function () {
+    let guard = new CallGuard();
+    try {
+        throw { value: 42, done: false };
+    } catch ({ value, done }) {
+        shouldBe(value, 42);
+        shouldBe(done, false);
+        guard.call();
+    }
+    shouldBe(guard.called, true);
+}());
+
+(function () {
+    let guard = new CallGuard();
+    try {
+        throw { value: 42, done: false };
+    } catch ({ value: v, done: d }) {
+        shouldBe(v, 42);
+        shouldBe(d, false);
+        guard.call();
+    }
+    shouldBe(guard.called, true);
+    // lexical
+    shouldBe(typeof v, "undefined");
+    shouldBe(typeof d, "undefined");
+}());
+
+shouldThrow(function () {
+    try {
+        throw { get error() { throw new Error("OK"); } };
+    } catch ({ error }) {
+    }
+}, `Error: OK`);
+
+let guard = new CallGuard();
+shouldThrow(function () {
+    try {
+        throw { get error() { throw new Error("OK"); } };
+    } catch ({ error }) {
+    } finally {
+        guard.call();
+    }
+}, `Error: OK`);
+shouldBe(guard.called, true);
+
+(function initialize() {
+    let guard = new CallGuard();
+    try {
+        throw { value: 42, done: false };
+    } catch ({ value, done, hello = 44 }) {
+        shouldBe(value, 42);
+        shouldBe(done, false);
+        shouldBe(hello, 44);
+        guard.call();
+    }
+    shouldBe(guard.called, true);
+}());
+
+(function array() {
+    let guard = new CallGuard();
+    try {
+        throw [0, 1, 2, 3, 4, 5];
+    } catch ([ a, b, c, ...d ]) {
+        shouldBe(a, 0);
+        shouldBe(b, 1);
+        shouldBe(c, 2);
+        shouldBe(JSON.stringify(d), `[3,4,5]`);
+        guard.call();
+    }
+    shouldBe(guard.called, true);
+}());
+
+(function generator() {
+    function *gen(v) {
+        try {
+            throw v;
+        } catch ({ value = yield 42 }) {
+            yield value;
+        }
+    }
+
+    {
+        let g = gen({});
+        {
+            let { value, done } = g.next();
+            shouldBe(value, 42);
+            shouldBe(done, false);
+        }
+        {
+            let { value, done } = g.next("OK");
+            shouldBe(value, "OK");
+            shouldBe(done, false);
+        }
+        {
+            let { value, done } = g.next("OK");
+            shouldBe(value, undefined);
+            shouldBe(done, true);
+        }
+    }
+
+    {
+        let g = gen({value: 400});
+        {
+            let { value, done } = g.next();
+            shouldBe(value, 400);
+            shouldBe(done, false);
+        }
+        {
+            let { value, done } = g.next("OK");
+            shouldBe(value, undefined);
+            shouldBe(done, true);
+        }
+    }
+}());
diff --git a/Source/JavaScriptCore/tests/stress/catch-parameter-syntax.js b/Source/JavaScriptCore/tests/stress/catch-parameter-syntax.js
new file mode 100644
index 0000000..d76457a
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/catch-parameter-syntax.js
@@ -0,0 +1,171 @@
+function testSyntax(script) {
+    try {
+        eval(script);
+    } catch (error) {
+        if (error instanceof SyntaxError)
+            throw new Error("Bad error: " + String(error));
+    }
+}
+
+function testSyntaxError(script, message) {
+    var error = null;
+    try {
+        eval(script);
+    } catch (e) {
+        error = e;
+    }
+    if (!error)
+        throw new Error("Expected syntax error not thrown");
+
+    if (String(error) !== message)
+        throw new Error("Bad error: " + String(error));
+}
+
+testSyntaxError(`
+(function () {
+    try {
+    } catch ([a, a]) {
+    }
+})
+`, `SyntaxError: Unexpected identifier 'a'. Cannot declare a lexical variable twice: 'a'.`);
+
+testSyntaxError(`
+(function () {
+    try {
+    } catch ({ a, b:a }) {
+    }
+})
+`, `SyntaxError: Unexpected identifier 'a'. Cannot declare a lexical variable twice: 'a'.`);
+
+testSyntax(`
+(function () {
+    try {
+    } catch (let) {
+    }
+})
+`, ``);
+
+testSyntax(`
+(function () {
+    try {
+    } catch ([let]) {
+    }
+})
+`, ``);
+
+testSyntaxError(`
+(function () {
+    'use strict';
+    try {
+    } catch (let) {
+    }
+})
+`, `SyntaxError: Cannot use the keyword 'let' as a catch parameter name.`);
+
+testSyntaxError(`
+(function () {
+    'use strict';
+    try {
+    } catch ([let]) {
+    }
+})
+`, `SyntaxError: Cannot use the keyword 'let' as a catch parameter name.`);
+
+
+testSyntax(`
+(function () {
+    try {
+    } catch (yield) {
+    }
+})
+`);
+
+testSyntax(`
+(function () {
+    try {
+    } catch ([yield]) {
+    }
+})
+`);
+
+testSyntaxError(`
+(function () {
+    'use strict';
+    try {
+    } catch (yield) {
+    }
+})
+`, `SyntaxError: Cannot use the keyword 'yield' as a catch parameter name.`);
+
+testSyntaxError(`
+(function () {
+    'use strict';
+    try {
+    } catch ([yield]) {
+    }
+})
+`, `SyntaxError: Cannot use the keyword 'yield' as a catch parameter name.`);
+
+testSyntaxError(`
+(function () {
+    try {
+    } catch (yield = 20) {
+    }
+})
+`, `SyntaxError: Unexpected token '='. Expected ')' to end a 'catch' target.`);
+
+testSyntax(`
+(function () {
+    try {
+    } catch ([...yield]) {
+    }
+})
+`);
+
+testSyntax(`
+(function () {
+    try {
+    } catch ([yield = 30]) {
+    }
+})
+`);
+
+testSyntax(`
+(function () {
+    try {
+    } catch ({ yield = 30 }) {
+    }
+})
+`);
+
+testSyntaxError(`
+(function () {
+    try {
+    } catch (...Hello) {
+    }
+})
+`, `SyntaxError: Unexpected token '...'. Expected a parameter pattern or a ')' in parameter list.`);
+
+testSyntaxError(`
+(function *() {
+    try {
+    } catch (yield) {
+    }
+})
+`, `SyntaxError: Cannot use the keyword 'yield' as a catch parameter name.`);
+
+testSyntax(`
+(function *() {
+    try {
+    } catch ({ value = yield 42 }) {
+    }
+})
+`);
+
+testSyntax(`
+(function *() {
+    try {
+    } catch ({ value = yield }) {
+    }
+})
+`);
diff --git a/Source/JavaScriptCore/tests/stress/reserved-word-with-escape.js b/Source/JavaScriptCore/tests/stress/reserved-word-with-escape.js
index 60335f2..f52dc4e 100644
--- a/Source/JavaScriptCore/tests/stress/reserved-word-with-escape.js
+++ b/Source/JavaScriptCore/tests/stress/reserved-word-with-escape.js
@@ -52,85 +52,85 @@
 testSyntaxError(String.raw`function v\u0061r() { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a function name.`);
 testSyntaxError(String.raw`function v\u{0061}r() { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a function name.`);
 
-testSyntaxError(String.raw`function a(var) { }`, String.raw`SyntaxError: Cannot use the keyword 'var' as a variable name.`);
-testSyntaxError(String.raw`function a(v\u0061r) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a variable name.`);
-testSyntaxError(String.raw`function a(v\u{0061}r) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a variable name.`);
+testSyntaxError(String.raw`function a(var) { }`, String.raw`SyntaxError: Cannot use the keyword 'var' as a parameter name.`);
+testSyntaxError(String.raw`function a(v\u0061r) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a parameter name.`);
+testSyntaxError(String.raw`function a(v\u{0061}r) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a parameter name.`);
 
 testSyntaxError(String.raw`function a({var}) { }`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 testSyntaxError(String.raw`function a({v\u0061r}) { }`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 testSyntaxError(String.raw`function a({v\u{0061}r}) { }`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 
-testSyntaxError(String.raw`function a({var:var}) { }`, String.raw`SyntaxError: Cannot use the keyword 'var' as a variable name.`);
-testSyntaxError(String.raw`function a({var:v\u0061r}) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a variable name.`);
-testSyntaxError(String.raw`function a({var:v\u{0061}r}) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a variable name.`);
+testSyntaxError(String.raw`function a({var:var}) { }`, String.raw`SyntaxError: Cannot use the keyword 'var' as a parameter name.`);
+testSyntaxError(String.raw`function a({var:v\u0061r}) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a parameter name.`);
+testSyntaxError(String.raw`function a({var:v\u{0061}r}) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a parameter name.`);
 
-testSyntaxError(String.raw`function a([var]) { }`, String.raw`SyntaxError: Cannot use the keyword 'var' as a variable name.`);
-testSyntaxError(String.raw`function a([v\u0061r]) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a variable name.`);
-testSyntaxError(String.raw`function a([v\u{0061}r]) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a variable name.`);
+testSyntaxError(String.raw`function a([var]) { }`, String.raw`SyntaxError: Cannot use the keyword 'var' as a parameter name.`);
+testSyntaxError(String.raw`function a([v\u0061r]) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a parameter name.`);
+testSyntaxError(String.raw`function a([v\u{0061}r]) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a parameter name.`);
 
 testSyntaxError(String.raw`(function var() { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a function name.`);
 testSyntaxError(String.raw`(function v\u0061r() { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a function name.`);
 testSyntaxError(String.raw`(function v\u{0061}r() { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a function name.`);
 
-testSyntaxError(String.raw`(function a(var) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a variable name.`);
-testSyntaxError(String.raw`(function a(v\u0061r) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a variable name.`);
-testSyntaxError(String.raw`(function a(v\u{0061}r) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a variable name.`);
+testSyntaxError(String.raw`(function a(var) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a parameter name.`);
+testSyntaxError(String.raw`(function a(v\u0061r) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a parameter name.`);
+testSyntaxError(String.raw`(function a(v\u{0061}r) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a parameter name.`);
 
 testSyntaxError(String.raw`(function a({var}) { })`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 testSyntaxError(String.raw`(function a({v\u0061r}) { })`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 testSyntaxError(String.raw`(function a({v\u{0061}r}) { })`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 
-testSyntaxError(String.raw`(function a({var:var}) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a variable name.`);
-testSyntaxError(String.raw`(function a({var:v\u0061r}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a variable name.`);
-testSyntaxError(String.raw`(function a({var:v\u{0061}r}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a variable name.`);
+testSyntaxError(String.raw`(function a({var:var}) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a parameter name.`);
+testSyntaxError(String.raw`(function a({var:v\u0061r}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a parameter name.`);
+testSyntaxError(String.raw`(function a({var:v\u{0061}r}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a parameter name.`);
 
-testSyntaxError(String.raw`(function a([var]) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a variable name.`);
-testSyntaxError(String.raw`(function a([v\u0061r]) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a variable name.`);
-testSyntaxError(String.raw`(function a([v\u{0061}r]) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a variable name.`);
+testSyntaxError(String.raw`(function a([var]) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a parameter name.`);
+testSyntaxError(String.raw`(function a([v\u0061r]) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a parameter name.`);
+testSyntaxError(String.raw`(function a([v\u{0061}r]) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a parameter name.`);
 
 testSyntaxError(String.raw`(function a([{var}]) { })`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 testSyntaxError(String.raw`(function a([{v\u0061r}]) { })`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 testSyntaxError(String.raw`(function a([{v\u{0061}r}]) { })`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 
-testSyntaxError(String.raw`(function a([{var:var}]) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a variable name.`);
-testSyntaxError(String.raw`(function a([{var:v\u0061r}]) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a variable name.`);
-testSyntaxError(String.raw`(function a([{var:v\u{0061}r}]) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a variable name.`);
+testSyntaxError(String.raw`(function a([{var:var}]) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a parameter name.`);
+testSyntaxError(String.raw`(function a([{var:v\u0061r}]) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a parameter name.`);
+testSyntaxError(String.raw`(function a([{var:v\u{0061}r}]) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a parameter name.`);
 
-testSyntaxError(String.raw`(function a([[var]]) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a variable name.`);
-testSyntaxError(String.raw`(function a([[v\u0061r]]) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a variable name.`);
-testSyntaxError(String.raw`(function a([[v\u{0061}r]]) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a variable name.`);
+testSyntaxError(String.raw`(function a([[var]]) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a parameter name.`);
+testSyntaxError(String.raw`(function a([[v\u0061r]]) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a parameter name.`);
+testSyntaxError(String.raw`(function a([[v\u{0061}r]]) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a parameter name.`);
 
 testSyntaxError(String.raw`(function a({ hello: {var}}) { })`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 testSyntaxError(String.raw`(function a({ hello: {v\u0061r}}) { })`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 testSyntaxError(String.raw`(function a({ hello: {v\u{0061}r}}) { })`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 
-testSyntaxError(String.raw`(function a({ hello: {var:var}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a variable name.`);
-testSyntaxError(String.raw`(function a({ hello: {var:v\u0061r}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a variable name.`);
-testSyntaxError(String.raw`(function a({ hello: {var:v\u{0061}r}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a variable name.`);
+testSyntaxError(String.raw`(function a({ hello: {var:var}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a parameter name.`);
+testSyntaxError(String.raw`(function a({ hello: {var:v\u0061r}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a parameter name.`);
+testSyntaxError(String.raw`(function a({ hello: {var:v\u{0061}r}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a parameter name.`);
 
-testSyntaxError(String.raw`(function a({ hello: [var]}) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a variable name.`);
-testSyntaxError(String.raw`(function a({ hello: [v\u0061r]}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a variable name.`);
-testSyntaxError(String.raw`(function a({ hello: [v\u{0061}r]}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a variable name.`);
+testSyntaxError(String.raw`(function a({ hello: [var]}) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a parameter name.`);
+testSyntaxError(String.raw`(function a({ hello: [v\u0061r]}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a parameter name.`);
+testSyntaxError(String.raw`(function a({ hello: [v\u{0061}r]}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a parameter name.`);
 
 testSyntaxError(String.raw`(function a({ 0: {var} }) { })`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 testSyntaxError(String.raw`(function a({ 0: {v\u0061r}}) { })`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 testSyntaxError(String.raw`(function a({ 0: {v\u{0061}r}}) { })`, String.raw`SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'var'.`);
 
-testSyntaxError(String.raw`(function a({ 0: {var:var}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a variable name.`);
-testSyntaxError(String.raw`(function a({ 0: {var:v\u0061r}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a variable name.`);
-testSyntaxError(String.raw`(function a({ 0: {var:v\u{0061}r}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a variable name.`);
+testSyntaxError(String.raw`(function a({ 0: {var:var}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a parameter name.`);
+testSyntaxError(String.raw`(function a({ 0: {var:v\u0061r}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a parameter name.`);
+testSyntaxError(String.raw`(function a({ 0: {var:v\u{0061}r}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a parameter name.`);
 
-testSyntaxError(String.raw`(function a({ 0: {value:var}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a variable name.`);
-testSyntaxError(String.raw`(function a({ 0: {value:v\u0061r}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a variable name.`);
-testSyntaxError(String.raw`(function a({ 0: {value:v\u{0061}r}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a variable name.`);
+testSyntaxError(String.raw`(function a({ 0: {value:var}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a parameter name.`);
+testSyntaxError(String.raw`(function a({ 0: {value:v\u0061r}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a parameter name.`);
+testSyntaxError(String.raw`(function a({ 0: {value:v\u{0061}r}}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a parameter name.`);
 
-testSyntaxError(String.raw`(function a({ 0: [var]}) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a variable name.`);
-testSyntaxError(String.raw`(function a({ 0: [v\u0061r]}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a variable name.`);
-testSyntaxError(String.raw`(function a({ 0: [v\u{0061}r]}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a variable name.`);
+testSyntaxError(String.raw`(function a({ 0: [var]}) { })`, String.raw`SyntaxError: Cannot use the keyword 'var' as a parameter name.`);
+testSyntaxError(String.raw`(function a({ 0: [v\u0061r]}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a parameter name.`);
+testSyntaxError(String.raw`(function a({ 0: [v\u{0061}r]}) { })`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a parameter name.`);
 
-testSyntaxError(String.raw`try { } catch(var) { }`, String.raw`SyntaxError: Cannot use the keyword 'var' as a catch variable name.`);
-testSyntaxError(String.raw`try { } catch(v\u0061r) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a catch variable name.`);
-testSyntaxError(String.raw`try { } catch(v\u{0061}r) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a catch variable name.`);
+testSyntaxError(String.raw`try { } catch(var) { }`, String.raw`SyntaxError: Cannot use the keyword 'var' as a catch parameter name.`);
+testSyntaxError(String.raw`try { } catch(v\u0061r) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a catch parameter name.`);
+testSyntaxError(String.raw`try { } catch(v\u{0061}r) { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u{0061}r' as a catch parameter name.`);
 
 testSyntaxError(String.raw`class var { }`, String.raw`SyntaxError: Cannot use the keyword 'var' as a class name.`);
 testSyntaxError(String.raw`class v\u0061r { }`, String.raw`SyntaxError: Cannot use the keyword 'v\u0061r' as a class name.`);
diff --git a/Source/JavaScriptCore/tests/stress/yield-named-variable.js b/Source/JavaScriptCore/tests/stress/yield-named-variable.js
index 51b4921..38bf6f8 100644
--- a/Source/JavaScriptCore/tests/stress/yield-named-variable.js
+++ b/Source/JavaScriptCore/tests/stress/yield-named-variable.js
@@ -48,13 +48,13 @@
     "use strict";
     let yield = 20;
 }
-`, `SyntaxError: Cannot use the keyword 'yield' as a variable name.`);
+`, `SyntaxError: Cannot use the keyword 'yield' as a lexical variable name.`);
 testSyntaxError(`
 function t1() {
     "use strict";
     const yield = 20;
 }
-`, `SyntaxError: Cannot use the keyword 'yield' as a variable name.`);
+`, `SyntaxError: Cannot use the keyword 'yield' as a lexical variable name.`);
 
 testSyntax(`
 function t1() {
@@ -118,13 +118,13 @@
     "use strict";
     let { i: yield } = 20;
 }
-`, `SyntaxError: Cannot use the keyword 'yield' as a variable name.`);
+`, `SyntaxError: Cannot use the keyword 'yield' as a lexical variable name.`);
 testSyntaxError(`
 function t1() {
     "use strict";
     const { i: yield } = 20;
 }
-`, `SyntaxError: Cannot use the keyword 'yield' as a variable name.`);
+`, `SyntaxError: Cannot use the keyword 'yield' as a lexical variable name.`);
 
 testSyntax(`
 function t1() {
@@ -153,13 +153,13 @@
     "use strict";
     let [ yield ] = 20;
 }
-`, `SyntaxError: Cannot use the keyword 'yield' as a variable name.`);
+`, `SyntaxError: Cannot use the keyword 'yield' as a lexical variable name.`);
 testSyntaxError(`
 function t1() {
     "use strict";
     const [ yield ] = 20;
 }
-`, `SyntaxError: Cannot use the keyword 'yield' as a variable name.`);
+`, `SyntaxError: Cannot use the keyword 'yield' as a lexical variable name.`);
 
 testSyntax(`
 function t1() {
@@ -187,7 +187,7 @@
     } catch (yield) {
     }
 }
-`, `SyntaxError: Cannot use the keyword 'yield' as a catch variable name.`);
+`, `SyntaxError: Cannot use the keyword 'yield' as a catch parameter name.`);
 
 testSyntax(`
 function t1() {