diff options
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilercontext.cpp | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilercontext_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilercontrolflow_p.h | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilerscanfunctions.cpp | 17 | ||||
-rw-r--r-- | src/qml/parser/qqmljs.g | 18 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast.cpp | 1 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast_p.h | 8 | ||||
-rw-r--r-- | tests/auto/qml/ecmascripttests/TestExpectations | 55 |
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 |