aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-05-08 14:34:58 +0200
committerLars Knoll <lars.knoll@qt.io>2018-05-11 07:17:12 +0000
commit01a1ad296c2b8325476abd6d28c8cc2463c42eb6 (patch)
tree4acaaf72782e634615e74c2da52227206cd16a42 /src
parent4cf7e80c5740912804383e4d866ba12b2520d0e6 (diff)
Support destructuring inside catch()
Change-Id: Ib60b56ac6a7111446e01235564a4cf92ad8ad025 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/compiler/qv4codegen.cpp6
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp4
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h2
-rw-r--r--src/qml/compiler/qv4compilercontrolflow_p.h4
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp17
-rw-r--r--src/qml/parser/qqmljs.g18
-rw-r--r--src/qml/parser/qqmljsast.cpp1
-rw-r--r--src/qml/parser/qqmljsast_p.h8
8 files changed, 42 insertions, 18 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index f55e6205dc..8c6964930d 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -2954,12 +2954,6 @@ bool Codegen::visit(ThrowStatement *ast)
void Codegen::handleTryCatch(TryStatement *ast)
{
Q_ASSERT(ast);
- if (_context->isStrict &&
- (ast->catchExpression->name == QLatin1String("eval") || ast->catchExpression->name == QLatin1String("arguments"))) {
- throwSyntaxError(ast->catchExpression->identifierToken, QStringLiteral("Catch variable name may not be eval or arguments in strict mode"));
- return;
- }
-
RegisterScope scope(this);
BytecodeGenerator::Label noException = bytecodeGenerator->newLabel();
{
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index 67afea28ab..07e19811a8 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -81,7 +81,7 @@ bool Context::addLocalVar(const QString &name, Context::MemberType type, Variabl
if (formals && formals->containsName(name))
return (scope == VariableScope::Var);
}
- if (!isCatchBlock || name != catchedVariable) {
+ if (!isCatchBlock || name != caughtVariable) {
MemberMap::iterator it = members.find(name);
if (it != members.end()) {
if (scope != VariableScope::Var || (*it).scope != VariableScope::Var)
@@ -178,7 +178,7 @@ int Context::emitBlockHeader(Codegen *codegen)
Instruction::PushCatchContext catchContext;
catchContext.index = blockIndex;
catchContext.reg = contextReg = bytecodeGenerator->newRegister();
- catchContext.name = codegen->registerString(catchedVariable);
+ catchContext.name = codegen->registerString(caughtVariable);
bytecodeGenerator->addInstruction(catchContext);
} else {
Instruction::PushBlockContext blockContext;
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index 20bee6583a..6838610d1c 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -155,7 +155,7 @@ struct Context {
bool requiresExecutionContext = false;
bool isWithBlock = false;
bool isCatchBlock = false;
- QString catchedVariable;
+ QString caughtVariable;
enum UsesArgumentsObject {
ArgumentsObjectUnknown,
diff --git a/src/qml/compiler/qv4compilercontrolflow_p.h b/src/qml/compiler/qv4compilercontrolflow_p.h
index b89226c411..db83af0022 100644
--- a/src/qml/compiler/qv4compilercontrolflow_p.h
+++ b/src/qml/compiler/qv4compilercontrolflow_p.h
@@ -422,6 +422,10 @@ struct ControlFlowCatch : public ControlFlowUnwind
Reference::storeConstOnStack(cg, QV4::Encode::undefined(), controlFlowTemp);
generator()->setExceptionHandler(&catchUnwindLabel);
+ if (catchExpression->patternElement->bindingIdentifier.isEmpty())
+ // destructuring pattern
+ cg->initializeAndDestructureBindingElement(catchExpression->patternElement, Reference::fromName(cg, QStringLiteral("@caught")));
+ // skip the additional block
cg->statementList(catchExpression->statement->statements);
insideCatch = false;
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp
index f7100a1d1a..4dbd11ef1c 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -387,8 +387,19 @@ bool ScanFunctions::visit(Catch *ast)
enterEnvironment(ast, ContextType::Block);
_context->name = QLatin1String("CatchBlock");
_context->isCatchBlock = true;
- _context->catchedVariable = ast->name.toString();
- _context->addLocalVar(ast->name.toString(), Context::MemberType::VariableDefinition, VariableScope::Let);
+ QString caughtVar = ast->patternElement->bindingIdentifier;
+ if (caughtVar.isEmpty())
+ caughtVar = QStringLiteral("@caught");
+ _context->addLocalVar(caughtVar, Context::MemberType::VariableDefinition, VariableScope::Let);
+
+ _context->caughtVariable = caughtVar;
+ if (_context->isStrict &&
+ (caughtVar == QLatin1String("eval") || caughtVar == QLatin1String("arguments"))) {
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Catch variable name may not be eval or arguments in strict mode"));
+ return false;
+ }
+ Node::accept(ast->patternElement, this);
+ // skip the block statement
Node::accept(ast->statement->statements, this);
return false;
}
@@ -567,7 +578,7 @@ void ScanFunctions::calcEscapingVariables()
}
if (c->contextType == ContextType::Block && c->isCatchBlock) {
c->requiresExecutionContext = true;
- auto m = c->members.find(c->catchedVariable);
+ auto m = c->members.find(c->caughtVariable);
m->canEscape = true;
}
if (allVarsEscape) {
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 8e71b8a42b..f162d123f5 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -3396,7 +3396,7 @@ TryStatement: T_TRY Block Catch Finally;
Catch: T_CATCH T_LPAREN CatchParameter T_RPAREN Block;
/.
case $rule_number: {
- AST::Catch *node = new (pool) AST::Catch(stringRef(3), sym(5).Block);
+ AST::Catch *node = new (pool) AST::Catch(sym(3).PatternElement, sym(5).Block);
node->catchToken = loc(1);
node->lparenToken = loc(2);
node->identifierToken = loc(3);
@@ -3415,9 +3415,23 @@ Finally: T_FINALLY Block;
./
CatchParameter: BindingIdentifier;
+/.
+ case $rule_number: {
+ AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(1));
+ node->identifierToken = loc(1);
+ node->scope = AST::VariableScope::Let;
+ sym(1).Node = node;
+ } break;
+./
CatchParameter: BindingPattern;
-/. case $rule_number: { UNIMPLEMENTED; } ./
+/.
+ case $rule_number: {
+ AST::PatternElement *node = new (pool) AST::PatternElement(sym(1).Pattern);
+ node->scope = AST::VariableScope::Let;
+ sym(1).Node = node;
+ } break;
+./
DebuggerStatement: T_DEBUGGER T_AUTOMATIC_SEMICOLON; -- automatic semicolon
DebuggerStatement: T_DEBUGGER T_SEMICOLON;
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index 6c0e394a34..cc8b290bc9 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -938,6 +938,7 @@ void TryStatement::accept0(Visitor *visitor)
void Catch::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
+ accept(patternElement, visitor);
accept(statement, visitor);
}
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index e54d1aea31..36060f7358 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -2063,9 +2063,9 @@ class QML_PARSER_EXPORT Catch: public Node
public:
QQMLJS_DECLARE_AST_NODE(Catch)
- Catch(const QStringRef &n, Block *stmt):
- name (n), statement (stmt)
- { kind = K; }
+ Catch(PatternElement *p, Block *stmt)
+ : patternElement(p), statement(stmt)
+ { kind = K; }
void accept0(Visitor *visitor) override;
@@ -2076,7 +2076,7 @@ public:
{ return statement->lastSourceLocation(); }
// attributes
- QStringRef name;
+ PatternElement *patternElement;
Block *statement;
SourceLocation catchToken;
SourceLocation lparenToken;