aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations55
9 files changed, 42 insertions, 73 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;
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index 1fcf546792..d438c15230 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -6849,44 +6849,16 @@ language/statements/try/cptn-finally-from-catch.js fails
language/statements/try/cptn-finally-skip-catch.js fails
language/statements/try/cptn-finally-wo-catch.js fails
language/statements/try/dstr-ary-init-iter-close.js fails
-language/statements/try/dstr-ary-init-iter-get-err.js fails
-language/statements/try/dstr-ary-init-iter-no-close.js fails
-language/statements/try/dstr-ary-name-iter-val.js fails
-language/statements/try/dstr-ary-ptrn-elem-ary-elem-init.js fails
-language/statements/try/dstr-ary-ptrn-elem-ary-elem-iter.js fails
language/statements/try/dstr-ary-ptrn-elem-ary-elision-init.js fails
-language/statements/try/dstr-ary-ptrn-elem-ary-elision-iter.js fails
-language/statements/try/dstr-ary-ptrn-elem-ary-empty-init.js fails
-language/statements/try/dstr-ary-ptrn-elem-ary-empty-iter.js fails
language/statements/try/dstr-ary-ptrn-elem-ary-rest-init.js fails
language/statements/try/dstr-ary-ptrn-elem-ary-rest-iter.js fails
-language/statements/try/dstr-ary-ptrn-elem-ary-val-null.js fails
-language/statements/try/dstr-ary-ptrn-elem-id-init-exhausted.js fails
language/statements/try/dstr-ary-ptrn-elem-id-init-fn-name-arrow.js fails
language/statements/try/dstr-ary-ptrn-elem-id-init-fn-name-class.js fails
language/statements/try/dstr-ary-ptrn-elem-id-init-fn-name-cover.js fails
language/statements/try/dstr-ary-ptrn-elem-id-init-fn-name-fn.js fails
language/statements/try/dstr-ary-ptrn-elem-id-init-fn-name-gen.js fails
-language/statements/try/dstr-ary-ptrn-elem-id-init-hole.js fails
-language/statements/try/dstr-ary-ptrn-elem-id-init-skipped.js fails
-language/statements/try/dstr-ary-ptrn-elem-id-init-throws.js fails
-language/statements/try/dstr-ary-ptrn-elem-id-init-undef.js fails
-language/statements/try/dstr-ary-ptrn-elem-id-init-unresolvable.js fails
-language/statements/try/dstr-ary-ptrn-elem-id-iter-complete.js fails
-language/statements/try/dstr-ary-ptrn-elem-id-iter-done.js fails
-language/statements/try/dstr-ary-ptrn-elem-id-iter-step-err.js fails
-language/statements/try/dstr-ary-ptrn-elem-id-iter-val-err.js fails
-language/statements/try/dstr-ary-ptrn-elem-id-iter-val.js fails
-language/statements/try/dstr-ary-ptrn-elem-obj-id-init.js fails
-language/statements/try/dstr-ary-ptrn-elem-obj-id.js fails
-language/statements/try/dstr-ary-ptrn-elem-obj-prop-id-init.js fails
-language/statements/try/dstr-ary-ptrn-elem-obj-prop-id.js fails
-language/statements/try/dstr-ary-ptrn-elem-obj-val-null.js fails
-language/statements/try/dstr-ary-ptrn-elem-obj-val-undef.js fails
-language/statements/try/dstr-ary-ptrn-elision-exhausted.js fails
language/statements/try/dstr-ary-ptrn-elision-step-err.js fails
language/statements/try/dstr-ary-ptrn-elision.js fails
-language/statements/try/dstr-ary-ptrn-empty.js fails
language/statements/try/dstr-ary-ptrn-rest-ary-elem.js fails
language/statements/try/dstr-ary-ptrn-rest-ary-elision.js fails
language/statements/try/dstr-ary-ptrn-rest-ary-empty.js fails
@@ -6899,39 +6871,12 @@ language/statements/try/dstr-ary-ptrn-rest-id-iter-val-err.js fails
language/statements/try/dstr-ary-ptrn-rest-id.js fails
language/statements/try/dstr-ary-ptrn-rest-obj-id.js fails
language/statements/try/dstr-ary-ptrn-rest-obj-prop-id.js fails
-language/statements/try/dstr-obj-init-null.js fails
-language/statements/try/dstr-obj-init-undefined.js fails
-language/statements/try/dstr-obj-ptrn-empty.js fails
-language/statements/try/dstr-obj-ptrn-id-get-value-err.js fails
language/statements/try/dstr-obj-ptrn-id-init-fn-name-arrow.js fails
language/statements/try/dstr-obj-ptrn-id-init-fn-name-class.js fails
language/statements/try/dstr-obj-ptrn-id-init-fn-name-cover.js fails
language/statements/try/dstr-obj-ptrn-id-init-fn-name-fn.js fails
language/statements/try/dstr-obj-ptrn-id-init-fn-name-gen.js fails
-language/statements/try/dstr-obj-ptrn-id-init-skipped.js fails
-language/statements/try/dstr-obj-ptrn-id-init-throws.js fails
-language/statements/try/dstr-obj-ptrn-id-init-unresolvable.js fails
-language/statements/try/dstr-obj-ptrn-id-trailing-comma.js fails
-language/statements/try/dstr-obj-ptrn-list-err.js fails
-language/statements/try/dstr-obj-ptrn-prop-ary-init.js fails
-language/statements/try/dstr-obj-ptrn-prop-ary-trailing-comma.js fails
-language/statements/try/dstr-obj-ptrn-prop-ary-value-null.js fails
-language/statements/try/dstr-obj-ptrn-prop-ary.js fails
-language/statements/try/dstr-obj-ptrn-prop-eval-err.js fails
-language/statements/try/dstr-obj-ptrn-prop-id-get-value-err.js fails
-language/statements/try/dstr-obj-ptrn-prop-id-init-skipped.js fails
-language/statements/try/dstr-obj-ptrn-prop-id-init-throws.js fails
-language/statements/try/dstr-obj-ptrn-prop-id-init-unresolvable.js fails
-language/statements/try/dstr-obj-ptrn-prop-id-init.js fails
-language/statements/try/dstr-obj-ptrn-prop-id-trailing-comma.js fails
-language/statements/try/dstr-obj-ptrn-prop-id.js fails
-language/statements/try/dstr-obj-ptrn-prop-obj-init.js fails
-language/statements/try/dstr-obj-ptrn-prop-obj-value-null.js fails
-language/statements/try/dstr-obj-ptrn-prop-obj-value-undef.js fails
-language/statements/try/dstr-obj-ptrn-prop-obj.js fails
language/statements/try/scope-catch-block-lex-open.js fails
-language/statements/try/scope-catch-param-lex-open.js fails
-language/statements/try/scope-catch-param-var-none.js sloppyFails
language/statements/try/tco-catch-finally.js strictFails
language/statements/try/tco-catch.js strictFails
language/statements/try/tco-finally.js strictFails