1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QJSENGINE_H
5#define QJSENGINE_H
6
7#include <QtCore/qmetatype.h>
8
9#include <QtCore/qvariant.h>
10#include <QtCore/qsharedpointer.h>
11#include <QtCore/qobject.h>
12#include <QtCore/qtimezone.h>
13#include <QtQml/qjsvalue.h>
14#include <QtQml/qjsmanagedvalue.h>
15#include <QtQml/qqmldebug.h>
16
17QT_BEGIN_NAMESPACE
18
19
20template <typename T>
21inline T qjsvalue_cast(const QJSValue &);
22
23class QJSEnginePrivate;
24class Q_QML_EXPORT QJSEngine
25 : public QObject
26{
27 Q_OBJECT
28 Q_PROPERTY(QString uiLanguage READ uiLanguage WRITE setUiLanguage NOTIFY uiLanguageChanged)
29public:
30 QJSEngine();
31 explicit QJSEngine(QObject *parent);
32 ~QJSEngine() override;
33
34 QJSValue globalObject() const;
35
36 QJSValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1, QStringList *exceptionStackTrace = nullptr);
37
38 QJSValue importModule(const QString &fileName);
39 bool registerModule(const QString &moduleName, const QJSValue &value);
40
41 QJSValue newObject();
42 QJSValue newSymbol(const QString &name);
43 QJSValue newArray(uint length = 0);
44
45 QJSValue newQObject(QObject *object);
46
47 QJSValue newQMetaObject(const QMetaObject* metaObject);
48
49 template <typename T>
50 QJSValue newQMetaObject()
51 {
52 return newQMetaObject(&T::staticMetaObject);
53 }
54
55 QJSValue newErrorObject(QJSValue::ErrorType errorType, const QString &message = QString());
56
57 template <typename T>
58 inline QJSValue toScriptValue(const T &value)
59 {
60 return create(type: QMetaType::fromType<T>(), ptr: &value);
61 }
62
63 template <typename T>
64 inline QJSManagedValue toManagedValue(const T &value)
65 {
66 return createManaged(type: QMetaType::fromType<T>(), ptr: &value);
67 }
68
69 template <typename T>
70 inline QJSPrimitiveValue toPrimitiveValue(const T &value)
71 {
72 // In the common case that the argument fits into QJSPrimitiveValue, use it.
73 if constexpr (std::disjunction_v<
74 std::is_same<T, int>,
75 std::is_same<T, bool>,
76 std::is_same<T, double>,
77 std::is_same<T, QString>>) {
78 return QJSPrimitiveValue(value);
79 } else {
80 return createPrimitive(type: QMetaType::fromType<T>(), ptr: &value);
81 }
82 }
83
84 template <typename T>
85 inline T fromScriptValue(const QJSValue &value)
86 {
87 return qjsvalue_cast<T>(value);
88 }
89
90 template <typename T>
91 inline T fromManagedValue(const QJSManagedValue &value)
92 {
93 return qjsvalue_cast<T>(value);
94 }
95
96 template <typename T>
97 inline T fromPrimitiveValue(const QJSPrimitiveValue &value)
98 {
99 if constexpr (std::is_same_v<T, int>)
100 return value.toInteger();
101 if constexpr (std::is_same_v<T, bool>)
102 return value.toBoolean();
103 if constexpr (std::is_same_v<T, double>)
104 return value.toDouble();
105 if constexpr (std::is_same_v<T, QString>)
106 return value.toString();
107 if constexpr (std::is_same_v<T, QVariant>)
108 return value.toVariant();
109 if constexpr (std::is_pointer_v<T>)
110 return nullptr;
111 return qjsvalue_cast<T>(value);
112 }
113
114 template <typename T>
115 inline T fromVariant(const QVariant &value)
116 {
117 if constexpr (std::is_same_v<T, QVariant>)
118 return value;
119
120 const QMetaType sourceType = value.metaType();
121 const QMetaType targetType = QMetaType::fromType<T>();
122 if (sourceType == targetType)
123 return *reinterpret_cast<const T *>(value.constData());
124
125 if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>) {
126 using nonConstT = std::remove_const_t<std::remove_pointer_t<T>> *;
127 const QMetaType nonConstTargetType = QMetaType::fromType<nonConstT>();
128 if (value.metaType() == nonConstTargetType)
129 return *reinterpret_cast<const nonConstT *>(value.constData());
130 }
131
132 if constexpr (std::is_same_v<T, QJSValue>)
133 return toScriptValue(value);
134
135 if constexpr (std::is_same_v<T, QJSManagedValue>)
136 return toManagedValue(value);
137
138 if constexpr (std::is_same_v<T, QJSPrimitiveValue>)
139 return toPrimitiveValue(value);
140
141 if constexpr (std::is_same_v<T, QString>) {
142 if (sourceType.flags() & QMetaType::PointerToQObject) {
143 return convertQObjectToString(
144 object: *reinterpret_cast<QObject *const *>(value.constData()));
145 }
146 }
147
148 if constexpr (std::is_same_v<QObject, std::remove_const_t<std::remove_pointer_t<T>>>) {
149 if (sourceType.flags() & QMetaType::PointerToQObject) {
150 return *static_cast<QObject *const *>(value.constData());
151
152 // We should not access source->metaObject() here since that may trigger some
153 // rather involved code. convertVariant() can do this using property caches.
154 }
155 }
156
157 if (sourceType == QMetaType::fromType<QJSValue>())
158 return fromScriptValue<T>(*reinterpret_cast<const QJSValue *>(value.constData()));
159
160 if (sourceType == QMetaType::fromType<QJSManagedValue>()) {
161 return fromManagedValue<T>(
162 *reinterpret_cast<const QJSManagedValue *>(value.constData()));
163 }
164
165 if (sourceType == QMetaType::fromType<QJSPrimitiveValue>()) {
166 return fromPrimitiveValue<T>(
167 *reinterpret_cast<const QJSPrimitiveValue *>(value.constData()));
168 }
169
170 {
171 T t{};
172 if (value.metaType() == QMetaType::fromType<QString>()) {
173 if (convertString(string: value.toString(), metaType: targetType, ptr: &t))
174 return t;
175 } else if (convertVariant(value, metaType: targetType, ptr: &t)) {
176 return t;
177 }
178
179 QMetaType::convert(value.metaType(), value.constData(), targetType, &t);
180 return t;
181 }
182 }
183
184 template<typename From, typename To>
185 inline To coerceValue(const From &from)
186 {
187 if constexpr (std::is_base_of_v<To, From>)
188 return from;
189
190 if constexpr (std::is_same_v<To, QJSValue>)
191 return toScriptValue(from);
192
193 if constexpr (std::is_same_v<From, QJSValue>)
194 return fromScriptValue<To>(from);
195
196 if constexpr (std::is_same_v<To, QJSManagedValue>)
197 return toManagedValue(from);
198
199 if constexpr (std::is_same_v<From, QJSManagedValue>)
200 return fromManagedValue<To>(from);
201
202 if constexpr (std::is_same_v<To, QJSPrimitiveValue>)
203 return toPrimitiveValue(from);
204
205 if constexpr (std::is_same_v<From, QJSPrimitiveValue>)
206 return fromPrimitiveValue<To>(from);
207
208 if constexpr (std::is_same_v<From, QVariant>)
209 return fromVariant<To>(from);
210
211 if constexpr (std::is_same_v<To, QVariant>)
212 return QVariant::fromValue(from);
213
214 if constexpr (std::is_same_v<To, QString>) {
215 if constexpr (std::is_base_of_v<QObject, std::remove_const_t<std::remove_pointer_t<From>>>)
216 return convertQObjectToString(object: from);
217 }
218
219 if constexpr (std::is_same_v<From, QDateTime>) {
220 if constexpr (std::is_same_v<To, QDate>)
221 return convertDateTimeToDate(dateTime: from.toLocalTime());
222 if constexpr (std::is_same_v<To, QTime>)
223 return from.toLocalTime().time();
224 if constexpr (std::is_same_v<To, QString>)
225 return convertDateTimeToString(dateTime: from.toLocalTime());
226 }
227
228 if constexpr (std::is_same_v<From, QDate>) {
229 if constexpr (std::is_same_v<To, QDateTime>)
230 return from.startOfDay(QTimeZone::UTC);
231 if constexpr (std::is_same_v<To, QTime>) {
232 // This is the current time zone offset, for better or worse
233 return coerceValue<QDateTime, QTime>(coerceValue<QDate, QDateTime>(from));
234 }
235 if constexpr (std::is_same_v<To, QString>)
236 return convertDateTimeToString(dateTime: coerceValue<QDate, QDateTime>(from));
237 }
238
239 if constexpr (std::is_same_v<From, QTime>) {
240 if constexpr (std::is_same_v<To, QDate>) {
241 // Yes. April Fools' 1971. See qv4dateobject.cpp.
242 return from.isValid() ? QDate(1971, 4, 1) : QDate();
243 }
244
245 if constexpr (std::is_same_v<To, QDateTime>)
246 return QDateTime(coerceValue<QTime, QDate>(from), from, QTimeZone::LocalTime);
247 if constexpr (std::is_same_v<To, QString>)
248 return convertDateTimeToString(dateTime: coerceValue<QTime, QDateTime>(from));
249 }
250
251 if constexpr (std::is_same_v<To, std::remove_const_t<std::remove_pointer_t<To>> const *>) {
252 using nonConstTo = std::remove_const_t<std::remove_pointer_t<To>> *;
253 if constexpr (std::is_same_v<From, nonConstTo>)
254 return from;
255 }
256
257 {
258 const QMetaType sourceType = QMetaType::fromType<From>();
259 const QMetaType targetType = QMetaType::fromType<To>();
260 To to{};
261 if constexpr (std::is_same_v<From, QString>) {
262 if (convertString(string: from, metaType: targetType, ptr: &to))
263 return to;
264 } else if (convertMetaType(fromType: sourceType, from: &from, toType: targetType, to: &to)) {
265 return to;
266 }
267
268 QMetaType::convert(sourceType, &from, targetType, &to);
269 return to;
270 }
271 }
272
273 void collectGarbage();
274
275 enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
276 static void setObjectOwnership(QObject *, ObjectOwnership);
277 static ObjectOwnership objectOwnership(QObject *);
278
279 enum Extension {
280 TranslationExtension = 0x1,
281 ConsoleExtension = 0x2,
282 GarbageCollectionExtension = 0x4,
283 AllExtensions = 0xffffffff
284 };
285 Q_DECLARE_FLAGS(Extensions, Extension)
286
287 void installExtensions(Extensions extensions, const QJSValue &object = QJSValue());
288
289 void setInterrupted(bool interrupted);
290 bool isInterrupted() const;
291
292 QV4::ExecutionEngine *handle() const { return m_v4Engine; }
293
294 void throwError(const QString &message);
295 void throwError(QJSValue::ErrorType errorType, const QString &message = QString());
296 void throwError(const QJSValue &error);
297 bool hasError() const;
298 QJSValue catchError();
299
300 QString uiLanguage() const;
301 void setUiLanguage(const QString &language);
302
303Q_SIGNALS:
304 void uiLanguageChanged();
305
306private:
307 QJSPrimitiveValue createPrimitive(QMetaType type, const void *ptr);
308 QJSManagedValue createManaged(QMetaType type, const void *ptr);
309 QJSValue create(QMetaType type, const void *ptr);
310#if QT_QML_REMOVED_SINCE(6, 5)
311 QJSValue create(int id, const void *ptr); // only there for BC reasons
312#endif
313
314 static bool convertPrimitive(const QJSPrimitiveValue &value, QMetaType type, void *ptr);
315 static bool convertManaged(const QJSManagedValue &value, int type, void *ptr);
316 static bool convertManaged(const QJSManagedValue &value, QMetaType type, void *ptr);
317#if QT_QML_REMOVED_SINCE(6, 5)
318 static bool convertV2(const QJSValue &value, int type, void *ptr); // only there for BC reasons
319#endif
320 static bool convertV2(const QJSValue &value, QMetaType metaType, void *ptr);
321 static bool convertString(const QString &string, QMetaType metaType, void *ptr);
322
323 bool convertVariant(const QVariant &value, QMetaType metaType, void *ptr);
324 bool convertMetaType(QMetaType fromType, const void *from, QMetaType toType, void *to);
325
326 QString convertQObjectToString(QObject *object);
327 QString convertDateTimeToString(const QDateTime &dateTime);
328 static QDate convertDateTimeToDate(const QDateTime &dateTime);
329
330 template<typename T>
331 friend inline T qjsvalue_cast(const QJSValue &);
332
333 template<typename T>
334 friend inline T qjsvalue_cast(const QJSManagedValue &);
335
336 template<typename T>
337 friend inline T qjsvalue_cast(const QJSPrimitiveValue &);
338
339protected:
340 QJSEngine(QJSEnginePrivate &dd, QObject *parent = nullptr);
341
342private:
343 QV4::ExecutionEngine *m_v4Engine;
344 Q_DISABLE_COPY(QJSEngine)
345 Q_DECLARE_PRIVATE(QJSEngine)
346};
347
348Q_DECLARE_OPERATORS_FOR_FLAGS(QJSEngine::Extensions)
349
350template<typename T>
351T qjsvalue_cast(const QJSValue &value)
352{
353 if (T t; QJSEngine::convertV2(value, metaType: QMetaType::fromType<T>(), ptr: &t))
354 return t;
355 else if (value.isVariant())
356 return qvariant_cast<T>(value.toVariant());
357
358 return T();
359}
360
361template<typename T>
362T qjsvalue_cast(const QJSManagedValue &value)
363{
364 if (T t; QJSEngine::convertManaged(value, QMetaType::fromType<T>(), &t))
365 return t;
366
367 return qvariant_cast<T>(value.toVariant());
368}
369
370template<typename T>
371T qjsvalue_cast(const QJSPrimitiveValue &value)
372{
373 if (T t; QJSEngine::convertPrimitive(value, type: QMetaType::fromType<T>(), ptr: &t))
374 return t;
375
376 return qvariant_cast<T>(value.toVariant());
377}
378
379template <>
380inline QVariant qjsvalue_cast<QVariant>(const QJSValue &value)
381{
382 return value.toVariant();
383}
384
385template <>
386inline QVariant qjsvalue_cast<QVariant>(const QJSManagedValue &value)
387{
388 return value.toVariant();
389}
390
391template <>
392inline QVariant qjsvalue_cast<QVariant>(const QJSPrimitiveValue &value)
393{
394 return value.toVariant();
395}
396
397Q_QML_EXPORT QJSEngine *qjsEngine(const QObject *);
398
399QT_END_NAMESPACE
400
401#endif // QJSENGINE_H
402

source code of qtdeclarative/src/qml/jsapi/qjsengine.h