aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/jsapi/qjsengine.cpp72
-rw-r--r--src/qml/jsapi/qjsengine.h3
-rw-r--r--src/qml/jsapi/qjsvalue.cpp53
-rw-r--r--src/qml/jsapi/qjsvalue.h12
-rw-r--r--src/qml/jsruntime/qv4engine.cpp15
-rw-r--r--src/qml/jsruntime/qv4engine_p.h3
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp63
7 files changed, 217 insertions, 4 deletions
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 69e1436c0a..3bde6a60c4 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -45,6 +45,7 @@
#include "private/qv4engine_p.h"
#include "private/qv4mm_p.h"
+#include "private/qv4errorobject_p.h"
#include "private/qv4globalobject_p.h"
#include "private/qv4script_p.h"
#include "private/qv4runtime_p.h"
@@ -583,6 +584,46 @@ QJSValue QJSEngine::newObject()
}
/*!
+ \since 5.12
+ Creates a JavaScript object of class Error.
+
+ The prototype of the created object will be \a errorType.
+
+ \sa newObject(), throwError(), QJSValue::isError()
+*/
+QJSValue QJSEngine::newErrorObject(QJSValue::ErrorType errorType, const QString &message)
+{
+ QV4::Scope scope(m_v4Engine);
+ QV4::ScopedObject error(scope);
+ switch (errorType) {
+ case QJSValue::RangeError:
+ error = m_v4Engine->newRangeErrorObject(message);
+ break;
+ case QJSValue::SyntaxError:
+ error = m_v4Engine->newSyntaxErrorObject(message);
+ break;
+ case QJSValue::TypeError:
+ error = m_v4Engine->newTypeErrorObject(message);
+ break;
+ case QJSValue::URIError:
+ error = m_v4Engine->newURIErrorObject(message);
+ break;
+ case QJSValue::ReferenceError:
+ error = m_v4Engine->newReferenceErrorObject(message);
+ break;
+ case QJSValue::EvalError:
+ error = m_v4Engine->newEvalErrorObject(message);
+ break;
+ case QJSValue::GenericError:
+ error = m_v4Engine->newErrorObject(message);
+ break;
+ case QJSValue::NoError:
+ return QJSValue::UndefinedValue;
+ }
+ return QJSValue(m_v4Engine, error->asReturnedValue());
+}
+
+/*!
Creates a JavaScript object of class Array with the given \a length.
\sa newObject()
@@ -894,6 +935,37 @@ void QJSEngine::throwError(const QString &message)
m_v4Engine->throwError(message);
}
+/*!
+ Throws a run-time error (exception) with the given \a errorType and
+ \a message.
+
+ \code
+ // Assuming that DataEntry is a QObject-derived class that has been
+ // registered as a singleton type and provides an invokable method
+ // setAge().
+
+ void DataEntry::setAge(int age) {
+ if (age < 0 || age > 200) {
+ jsEngine->throwError(QJSValue::RangeError,
+ "Age must be between 0 and 200");
+ }
+ ...
+ }
+ \endcode
+
+ \since Qt 5.12
+ \sa {Script Exceptions}, newErrorObject()
+*/
+void QJSEngine::throwError(QJSValue::ErrorType errorType, const QString &message)
+{
+ QV4::Scope scope(m_v4Engine);
+ QJSValue error = newErrorObject(errorType, message);
+ QV4::ScopedObject e(scope, QJSValuePrivate::getValue(&error));
+ if (!e)
+ return;
+ m_v4Engine->throwError(e);
+}
+
QJSEnginePrivate *QJSEnginePrivate::get(QV4::ExecutionEngine *e)
{
return e->jsEngine()->d_func();
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index 5c8613ffd6..6300842341 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -84,6 +84,8 @@ public:
return newQMetaObject(&T::staticMetaObject);
}
+ QJSValue newErrorObject(QJSValue::ErrorType errorType, const QString &message = QString());
+
template <typename T>
inline QJSValue toScriptValue(const T &value)
{
@@ -114,6 +116,7 @@ public:
QV4::ExecutionEngine *handle() const { return m_v4Engine; }
void throwError(const QString &message);
+ void throwError(QJSValue::ErrorType errorType, const QString &message = QString());
private:
QJSValue create(int type, const void *ptr);
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 9671e82187..14baf0ac10 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -159,6 +159,22 @@
This is a typedef for a QList<QJSValue>.
*/
+/*!
+ \enum QJSValue::ErrorType
+ \since 5.12
+
+ This enum is used to specify a type of Error object.
+
+ \value NoError Not an Error object.
+ \value GenericError A generic Error object, but not of a specific sub-type.
+ \value EvalError An error regarding the global eval() function.
+ \value RangeError A value did not match the expected set or range.
+ \value ReferenceError A non-existing variable referenced.
+ \value SyntaxError Invalid syntax.
+ \value TypeError A value did not match the expected type.
+ \value URIError A URI handling function was used incorrectly.
+*/
+
QT_BEGIN_NAMESPACE
using namespace QV4;
@@ -371,7 +387,7 @@ bool QJSValue::isUndefined() const
Returns true if this QJSValue is an object of the Error class;
otherwise returns false.
- \sa {QJSEngine#Script Exceptions}{QJSEngine - Script Exceptions}
+ \sa errorType(), {QJSEngine#Script Exceptions}{QJSEngine - Script Exceptions}
*/
bool QJSValue::isError() const
{
@@ -382,6 +398,41 @@ bool QJSValue::isError() const
}
/*!
+ \since 5.12
+ Returns the error type this QJSValue represents if it is an Error object.
+ Otherwise, returns \c NoError."
+
+ \sa isError(), {QJSEngine#Script Exceptions}{QJSEngine - Script Exceptions}
+*/
+QJSValue::ErrorType QJSValue::errorType() const
+{
+ QV4::Value *val = QJSValuePrivate::getValue(this);
+ if (!val)
+ return NoError;
+ QV4::ErrorObject *error = val->as<ErrorObject>();
+ if (!error)
+ return NoError;
+ switch (error->d()->errorType) {
+ case QV4::Heap::ErrorObject::Error:
+ return GenericError;
+ case QV4::Heap::ErrorObject::EvalError:
+ return EvalError;
+ case QV4::Heap::ErrorObject::RangeError:
+ return RangeError;
+ case QV4::Heap::ErrorObject::ReferenceError:
+ return ReferenceError;
+ case QV4::Heap::ErrorObject::SyntaxError:
+ return SyntaxError;
+ case QV4::Heap::ErrorObject::TypeError:
+ return TypeError;
+ case QV4::Heap::ErrorObject::URIError:
+ return URIError;
+ }
+ Q_UNREACHABLE();
+ return NoError;
+}
+
+/*!
Returns true if this QJSValue is an object of the Array class;
otherwise returns false.
diff --git a/src/qml/jsapi/qjsvalue.h b/src/qml/jsapi/qjsvalue.h
index 56bd64eec1..2f95e0ff31 100644
--- a/src/qml/jsapi/qjsvalue.h
+++ b/src/qml/jsapi/qjsvalue.h
@@ -68,6 +68,17 @@ public:
UndefinedValue
};
+ enum ErrorType {
+ NoError,
+ GenericError,
+ EvalError,
+ RangeError,
+ ReferenceError,
+ SyntaxError,
+ TypeError,
+ URIError
+ };
+
public:
QJSValue(SpecialValue value = UndefinedValue);
~QJSValue();
@@ -137,6 +148,7 @@ public:
QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
QJSValue callAsConstructor(const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
+ ErrorType errorType() const;
#ifdef QT_DEPRECATED
QT_DEPRECATED QJSEngine *engine() const;
#endif
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 129bb20019..169ab0a4a4 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -849,6 +849,11 @@ Heap::Object *ExecutionEngine::newErrorObject(const Value &value)
return ErrorObject::create<ErrorObject>(this, value, errorCtor());
}
+Heap::Object *ExecutionEngine::newErrorObject(const QString &message)
+{
+ return ErrorObject::create<ErrorObject>(this, message);
+}
+
Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message)
{
return ErrorObject::create<SyntaxErrorObject>(this, message);
@@ -918,6 +923,16 @@ Promise::ReactionHandler *ExecutionEngine::getPromiseReactionHandler()
return m_reactionHandler.data();
}
+Heap::Object *ExecutionEngine::newURIErrorObject(const QString &message)
+{
+ return ErrorObject::create<URIErrorObject>(this, message);
+}
+
+Heap::Object *ExecutionEngine::newEvalErrorObject(const QString &message)
+{
+ return ErrorObject::create<EvalErrorObject>(this, message);
+}
+
Heap::Object *ExecutionEngine::newVariantObject(const QVariant &v)
{
return memoryManager->allocate<VariantObject>(v);
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 928c9f4947..64c7e2f32b 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -522,13 +522,16 @@ public:
Heap::RegExpObject *newRegExpObject(const QRegExp &re);
Heap::Object *newErrorObject(const Value &value);
+ Heap::Object *newErrorObject(const QString &message);
Heap::Object *newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column);
Heap::Object *newSyntaxErrorObject(const QString &message);
Heap::Object *newReferenceErrorObject(const QString &message);
Heap::Object *newReferenceErrorObject(const QString &message, const QString &fileName, int line, int column);
Heap::Object *newTypeErrorObject(const QString &message);
Heap::Object *newRangeErrorObject(const QString &message);
+ Heap::Object *newURIErrorObject(const QString &message);
Heap::Object *newURIErrorObject(const Value &message);
+ Heap::Object *newEvalErrorObject(const QString &message);
Heap::PromiseObject *newPromiseObject();
Heap::Object *newPromiseObject(const QV4::FunctionObject *thisObject, const QV4::PromiseCapability *capability);
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index a38224ef81..00c631141b 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -224,6 +224,8 @@ private slots:
void multilineStrings();
void throwError();
+ void throwErrorObject();
+ void returnError();
void mathMinMax();
void importModule();
@@ -232,7 +234,9 @@ private slots:
void importExportErrors();
public:
- Q_INVOKABLE QJSValue throwingCppMethod();
+ Q_INVOKABLE QJSValue throwingCppMethod1();
+ Q_INVOKABLE void throwingCppMethod2();
+ Q_INVOKABLE QJSValue throwingCppMethod3();
signals:
void testSignal();
@@ -4384,7 +4388,7 @@ void tst_QJSEngine::throwError()
QJSValue result = engine.evaluate(
"function test(){\n"
"try {\n"
- " return testCase.throwingCppMethod();\n"
+ " return testCase.throwingCppMethod1();\n"
"} catch (error) {\n"
" return error;\n"
"}\n"
@@ -4393,17 +4397,70 @@ void tst_QJSEngine::throwError()
"test();"
);
QVERIFY(result.isError());
+ QCOMPARE(result.errorType(), QJSValue::GenericError);
QCOMPARE(result.property("lineNumber").toString(), "3");
QCOMPARE(result.property("message").toString(), "blub");
QVERIFY(!result.property("stack").isUndefined());
}
-QJSValue tst_QJSEngine::throwingCppMethod()
+void tst_QJSEngine::throwErrorObject()
+{
+ QJSEngine engine;
+ QJSValue wrappedThis = engine.newQObject(this);
+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
+ engine.globalObject().setProperty("testCase", wrappedThis);
+
+ QJSValue result = engine.evaluate(
+ "function test(){\n"
+ " try {\n"
+ " testCase.throwingCppMethod2();\n"
+ " } catch (error) {\n"
+ " if (error instanceof TypeError) {\n"
+ " return error;\n"
+ " }\n"
+ " }\n"
+ " return null;\n"
+ "}\n"
+ "test();"
+ );
+ QVERIFY(result.isError());
+ QCOMPARE(result.errorType(), QJSValue::TypeError);
+ QCOMPARE(result.property("lineNumber").toString(), "3");
+ QCOMPARE(result.property("message").toString(), "Wrong type");
+ QVERIFY(!result.property("stack").isUndefined());
+}
+
+void tst_QJSEngine::returnError()
+{
+ QJSEngine engine;
+ QJSValue wrappedThis = engine.newQObject(this);
+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
+ engine.globalObject().setProperty("testCase", wrappedThis);
+
+ QJSValue result = engine.evaluate("testCase.throwingCppMethod3()");
+ QVERIFY(result.isError());
+ QCOMPARE(result.errorType(), QJSValue::EvalError);
+ QCOMPARE(result.property("lineNumber").toString(), "1");
+ QCOMPARE(result.property("message").toString(), "Something is wrong");
+ QVERIFY(!result.property("stack").isUndefined());
+}
+
+QJSValue tst_QJSEngine::throwingCppMethod1()
{
qjsEngine(this)->throwError("blub");
return QJSValue(47);
}
+void tst_QJSEngine::throwingCppMethod2()
+{
+ qjsEngine(this)->throwError(QJSValue::TypeError, "Wrong type");
+}
+
+QJSValue tst_QJSEngine::throwingCppMethod3()
+{
+ return qjsEngine(this)->newErrorObject(QJSValue::EvalError, "Something is wrong");
+}
+
void tst_QJSEngine::mathMinMax()
{
QJSEngine engine;