Support QRegularExpression on the same level as QRegExp
QRegularExpression is the recommended way to do regular expressions nowadays. Support assignment of JavaScript regular expressions to QRegularExpression properties of QObjects and the other way around. QJSValue::toVariant() will create a QRegularExpression from a JavaScript RegExp by default now. [ChangeLog][QtQml][Important Behavior Changes] QRegularExpression is now supported the same way QRegExp is in QML. QJSValue::toVariant() creates a QRegularExpression variant rather than a QRegExp one from a JavaScript regular expression now. Fixes: QTBUG-73429 Change-Id: I301a02771cd17903406c2bc5c7aaeca6cce629f0 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
parent
80920a3012
commit
d2fd8010d3
|
@ -558,6 +558,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
|
|||
}
|
||||
break;
|
||||
case QVariant::RegExp:
|
||||
case QVariant::RegularExpression:
|
||||
return warnOrError(tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
|
||||
default: {
|
||||
// generate single literal value assignment to a list property if required
|
||||
|
|
|
@ -51,6 +51,9 @@
|
|||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QLoggingCategory>
|
||||
#if QT_CONFIG(regularexpression)
|
||||
#include <QRegularExpression>
|
||||
#endif
|
||||
|
||||
#ifndef V4_BOOTSTRAP
|
||||
|
||||
|
@ -854,6 +857,13 @@ Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re)
|
|||
return memoryManager->allocate<RegExpObject>(re);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(regularexpression)
|
||||
Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegularExpression &re)
|
||||
{
|
||||
return memoryManager->allocate<RegExpObject>(re);
|
||||
}
|
||||
#endif
|
||||
|
||||
Heap::Object *ExecutionEngine::newErrorObject(const Value &value)
|
||||
{
|
||||
return ErrorObject::create<ErrorObject>(this, value, errorCtor());
|
||||
|
@ -1365,8 +1375,13 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
|
|||
QV4::ScopedObject o(scope, value);
|
||||
Q_ASSERT(o);
|
||||
|
||||
if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>())
|
||||
if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>()) {
|
||||
#if QT_CONFIG(regularexpression)
|
||||
if (typeHint != QMetaType::QRegExp)
|
||||
return re->toQRegularExpression();
|
||||
#endif
|
||||
return re->toQRegExp();
|
||||
}
|
||||
|
||||
if (createJSValueForObjects)
|
||||
return QVariant::fromValue(QJSValue(scope.engine, o->asReturnedValue()));
|
||||
|
@ -1455,8 +1470,6 @@ static QV4::ReturnedValue objectFromVariantMap(QV4::ExecutionEngine *e, const QV
|
|||
return o.asReturnedValue();
|
||||
}
|
||||
|
||||
Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
|
||||
|
||||
QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
|
||||
{
|
||||
int type = variant.userType();
|
||||
|
@ -1506,6 +1519,10 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
|
|||
return QV4::Encode(newDateObjectFromTime(*reinterpret_cast<const QTime *>(ptr)));
|
||||
case QMetaType::QRegExp:
|
||||
return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(ptr)));
|
||||
#if QT_CONFIG(regularexpression)
|
||||
case QMetaType::QRegularExpression:
|
||||
return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegularExpression *>(ptr)));
|
||||
#endif
|
||||
case QMetaType::QObjectStar:
|
||||
return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
|
||||
#if QT_CONFIG(qml_sequence_object)
|
||||
|
@ -1713,6 +1730,10 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
|
|||
return QV4::Encode(newDateObject(QDateTime(*reinterpret_cast<const QDate *>(data))));
|
||||
case QMetaType::QRegExp:
|
||||
return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(data)));
|
||||
#if QT_CONFIG(regularexpression)
|
||||
case QMetaType::QRegularExpression:
|
||||
return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegularExpression *>(data)));
|
||||
#endif
|
||||
case QMetaType::QObjectStar:
|
||||
return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(data));
|
||||
case QMetaType::QVariant:
|
||||
|
@ -1955,6 +1976,13 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
|
|||
*reinterpret_cast<QRegExp *>(data) = r->toQRegExp();
|
||||
return true;
|
||||
} break;
|
||||
#if QT_CONFIG(regularexpression)
|
||||
case QMetaType::QRegularExpression:
|
||||
if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) {
|
||||
*reinterpret_cast<QRegularExpression *>(data) = r->toQRegularExpression();
|
||||
return true;
|
||||
} break;
|
||||
#endif
|
||||
case QMetaType::QObjectStar: {
|
||||
const QV4::QObjectWrapper *qobjectWrapper = value->as<QV4::QObjectWrapper>();
|
||||
if (qobjectWrapper || value->isNull()) {
|
||||
|
|
|
@ -520,6 +520,9 @@ public:
|
|||
Heap::RegExpObject *newRegExpObject(const QString &pattern, int flags);
|
||||
Heap::RegExpObject *newRegExpObject(RegExp *re);
|
||||
Heap::RegExpObject *newRegExpObject(const QRegExp &re);
|
||||
#if QT_CONFIG(regularexpression)
|
||||
Heap::RegExpObject *newRegExpObject(const QRegularExpression &re);
|
||||
#endif
|
||||
|
||||
Heap::Object *newErrorObject(const Value &value);
|
||||
Heap::Object *newErrorObject(const QString &message);
|
||||
|
|
|
@ -1317,6 +1317,9 @@ static int MatchScore(const QV4::Value &actual, int conversionType)
|
|||
} else if (actual.as<QV4::RegExpObject>()) {
|
||||
switch (conversionType) {
|
||||
case QMetaType::QRegExp:
|
||||
#if QT_CONFIG(regularexpression)
|
||||
case QMetaType::QRegularExpression:
|
||||
#endif
|
||||
return 0;
|
||||
default:
|
||||
return 10;
|
||||
|
|
|
@ -50,6 +50,9 @@
|
|||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/qregexp.h>
|
||||
#if QT_CONFIG(regularexpression)
|
||||
#include <QtCore/qregularexpression.h>
|
||||
#endif
|
||||
#include <cassert>
|
||||
#include <typeinfo>
|
||||
#include <iostream>
|
||||
|
@ -134,6 +137,25 @@ void Heap::RegExpObject::init(const QRegExp &re)
|
|||
o->initProperties();
|
||||
}
|
||||
|
||||
#if QT_CONFIG(regularexpression)
|
||||
// Converts a QRegularExpression to a JS RegExp.
|
||||
// The conversion is not 100% exact since ECMA regexp and QRegularExpression
|
||||
// have different semantics/flags, but we try to do our best.
|
||||
void Heap::RegExpObject::init(const QRegularExpression &re)
|
||||
{
|
||||
Object::init();
|
||||
|
||||
Scope scope(internalClass->engine);
|
||||
Scoped<QV4::RegExpObject> o(scope, this);
|
||||
|
||||
const uint flags = (re.patternOptions() & QRegularExpression::CaseInsensitiveOption)
|
||||
? CompiledData::RegExp::RegExp_IgnoreCase
|
||||
: CompiledData::RegExp::RegExp_NoFlags;
|
||||
o->d()->value.set(scope.engine, QV4::RegExp::create(scope.engine, re.pattern(), flags));
|
||||
o->initProperties();
|
||||
}
|
||||
#endif
|
||||
|
||||
void RegExpObject::initProperties()
|
||||
{
|
||||
setProperty(Index_LastIndex, Value::fromInt32(0));
|
||||
|
@ -150,6 +172,20 @@ QRegExp RegExpObject::toQRegExp() const
|
|||
return QRegExp(*value()->pattern, caseSensitivity, QRegExp::RegExp2);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(regularexpression)
|
||||
// Converts a JS RegExp to a QRegularExpression.
|
||||
// The conversion is not 100% exact since ECMA regexp and QRegularExpression
|
||||
// have different semantics/flags, but we try to do our best.
|
||||
QRegularExpression RegExpObject::toQRegularExpression() const
|
||||
{
|
||||
QRegularExpression::PatternOptions caseSensitivity
|
||||
= (value()->flags & CompiledData::RegExp::RegExp_IgnoreCase)
|
||||
? QRegularExpression::CaseInsensitiveOption
|
||||
: QRegularExpression::NoPatternOption;
|
||||
return QRegularExpression(*value()->pattern, caseSensitivity);
|
||||
}
|
||||
#endif
|
||||
|
||||
QString RegExpObject::toString() const
|
||||
{
|
||||
QString p = *value()->pattern;
|
||||
|
|
|
@ -81,6 +81,9 @@ DECLARE_HEAP_OBJECT(RegExpObject, Object) {
|
|||
void init();
|
||||
void init(QV4::RegExp *value);
|
||||
void init(const QRegExp &re);
|
||||
#if QT_CONFIG(regularexpression)
|
||||
void init(const QRegularExpression &re);
|
||||
#endif
|
||||
};
|
||||
|
||||
#define RegExpCtorMembers(class, Member) \
|
||||
|
@ -138,6 +141,9 @@ struct RegExpObject: Object {
|
|||
}
|
||||
|
||||
QRegExp toQRegExp() const;
|
||||
#if QT_CONFIG(regularexpression)
|
||||
QRegularExpression toQRegularExpression() const;
|
||||
#endif
|
||||
QString toString() const;
|
||||
QString source() const;
|
||||
|
||||
|
|
|
@ -62,7 +62,9 @@
|
|||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QDir>
|
||||
#if QT_CONFIG(regularexpression)
|
||||
#include <QtCore/qregularexpression.h>
|
||||
#endif
|
||||
#include <QtQuick/qquickwindow.h>
|
||||
#include <QtGui/qvector3d.h>
|
||||
#include <QtGui/qimagewriter.h>
|
||||
|
@ -640,12 +642,9 @@ void QuickTestResult::warn(const QString &message, const QUrl &location, int lin
|
|||
void QuickTestResult::ignoreWarning(const QJSValue &message)
|
||||
{
|
||||
if (message.isRegExp()) {
|
||||
// ### we should probably handle QRegularExpression conversion engine-side
|
||||
QRegExp re = message.toVariant().toRegExp();
|
||||
QRegularExpression::PatternOptions opts = re.caseSensitivity() ==
|
||||
Qt::CaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption;
|
||||
QRegularExpression re2(re.pattern(), opts);
|
||||
QTestLog::ignoreMessage(QtWarningMsg, re2);
|
||||
#if QT_CONFIG(regularexpression)
|
||||
QTestLog::ignoreMessage(QtWarningMsg, message.toVariant().toRegularExpression());
|
||||
#endif
|
||||
} else {
|
||||
QTestLog::ignoreMessage(QtWarningMsg, message.toString().toLatin1());
|
||||
}
|
||||
|
|
|
@ -94,6 +94,7 @@ private slots:
|
|||
void valueConversion_basic2();
|
||||
void valueConversion_dateTime();
|
||||
void valueConversion_regExp();
|
||||
void valueConversion_RegularExpression();
|
||||
void castWithMultipleInheritance();
|
||||
void collectGarbage();
|
||||
void gcWithNestedDataStructure();
|
||||
|
@ -135,6 +136,8 @@ private slots:
|
|||
|
||||
void qRegExpInport_data();
|
||||
void qRegExpInport();
|
||||
void qRegularExpressionImport_data();
|
||||
void qRegularExpressionImport();
|
||||
void dateRoundtripJSQtJS();
|
||||
void dateRoundtripQtJSQt();
|
||||
void dateConversionJSQt();
|
||||
|
@ -520,22 +523,27 @@ void tst_QJSEngine::newVariant_valueOfEnum()
|
|||
void tst_QJSEngine::newRegExp()
|
||||
{
|
||||
QJSEngine eng;
|
||||
QJSValue rexp = eng.toScriptValue(QRegExp("foo"));
|
||||
QVERIFY(!rexp.isUndefined());
|
||||
QCOMPARE(rexp.isRegExp(), true);
|
||||
QCOMPARE(rexp.isObject(), true);
|
||||
QCOMPARE(rexp.isCallable(), false);
|
||||
// prototype should be RegExp.prototype
|
||||
QVERIFY(!rexp.prototype().isUndefined());
|
||||
QCOMPARE(rexp.prototype().isObject(), true);
|
||||
// Get [[Class]] internal property of RegExp Prototype Object.
|
||||
// See ECMA-262 Section 8.6.2, "Object Internal Properties and Methods".
|
||||
// See ECMA-262 Section 15.10.6, "Properties of the RegExp Prototype Object".
|
||||
QJSValue r = eng.evaluate("Object.prototype.toString.call(RegExp.prototype)");
|
||||
QCOMPARE(r.toString(), QString::fromLatin1("[object Object]"));
|
||||
QCOMPARE(rexp.prototype().strictlyEquals(eng.evaluate("RegExp.prototype")), true);
|
||||
QJSValue rexps[] = {
|
||||
eng.toScriptValue(QRegularExpression("foo")),
|
||||
eng.toScriptValue(QRegExp("foo"))
|
||||
};
|
||||
for (const auto &rexp : rexps) {
|
||||
QVERIFY(!rexp.isUndefined());
|
||||
QCOMPARE(rexp.isRegExp(), true);
|
||||
QCOMPARE(rexp.isObject(), true);
|
||||
QCOMPARE(rexp.isCallable(), false);
|
||||
// prototype should be RegExp.prototype
|
||||
QVERIFY(!rexp.prototype().isUndefined());
|
||||
QCOMPARE(rexp.prototype().isObject(), true);
|
||||
// Get [[Class]] internal property of RegExp Prototype Object.
|
||||
// See ECMA-262 Section 8.6.2, "Object Internal Properties and Methods".
|
||||
// See ECMA-262 Section 15.10.6, "Properties of the RegExp Prototype Object".
|
||||
QJSValue r = eng.evaluate("Object.prototype.toString.call(RegExp.prototype)");
|
||||
QCOMPARE(r.toString(), QString::fromLatin1("[object Object]"));
|
||||
QCOMPARE(rexp.prototype().strictlyEquals(eng.evaluate("RegExp.prototype")), true);
|
||||
|
||||
QCOMPARE(qjsvalue_cast<QRegExp>(rexp).pattern(), QRegExp("foo").pattern());
|
||||
QCOMPARE(qjsvalue_cast<QRegExp>(rexp).pattern(), QRegExp("foo").pattern());
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QJSEngine::jsRegExp()
|
||||
|
@ -1601,6 +1609,28 @@ void tst_QJSEngine::valueConversion_regExp()
|
|||
}
|
||||
}
|
||||
|
||||
void tst_QJSEngine::valueConversion_RegularExpression()
|
||||
{
|
||||
QJSEngine eng;
|
||||
{
|
||||
QRegularExpression in = QRegularExpression("foo");
|
||||
QJSValue val = eng.toScriptValue(in);
|
||||
QVERIFY(val.isRegExp());
|
||||
QRegularExpression out = qjsvalue_cast<QRegularExpression>(val);
|
||||
QCOMPARE(out.pattern(), in.pattern());
|
||||
QCOMPARE(out.patternOptions(), in.patternOptions());
|
||||
}
|
||||
{
|
||||
QRegularExpression in = QRegularExpression("foo",
|
||||
QRegularExpression::CaseInsensitiveOption);
|
||||
QJSValue val = eng.toScriptValue(in);
|
||||
QVERIFY(val.isRegExp());
|
||||
QCOMPARE(qjsvalue_cast<QRegularExpression>(val), in);
|
||||
QRegularExpression out = qjsvalue_cast<QRegularExpression>(val);
|
||||
QCOMPARE(out.patternOptions(), in.patternOptions());
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(QGradient)
|
||||
Q_DECLARE_METATYPE(QGradient*)
|
||||
Q_DECLARE_METATYPE(QLinearGradient)
|
||||
|
@ -2950,6 +2980,8 @@ void tst_QJSEngine::reentrancy_objectCreation()
|
|||
QJSValue r2 = eng2.evaluate("new RegExp('foo', 'gim')");
|
||||
QCOMPARE(qjsvalue_cast<QRegExp>(r1), qjsvalue_cast<QRegExp>(r2));
|
||||
QCOMPARE(qjsvalue_cast<QRegExp>(r2), qjsvalue_cast<QRegExp>(r1));
|
||||
QCOMPARE(qjsvalue_cast<QRegularExpression>(r1), qjsvalue_cast<QRegularExpression>(r2));
|
||||
QCOMPARE(qjsvalue_cast<QRegularExpression>(r2), qjsvalue_cast<QRegularExpression>(r1));
|
||||
}
|
||||
{
|
||||
QJSValue o1 = eng1.newQObject(temp);
|
||||
|
@ -3145,6 +3177,56 @@ void tst_QJSEngine::qRegExpInport()
|
|||
}
|
||||
}
|
||||
|
||||
void tst_QJSEngine::qRegularExpressionImport_data()
|
||||
{
|
||||
QTest::addColumn<QRegularExpression>("rx");
|
||||
QTest::addColumn<QString>("string");
|
||||
QTest::addColumn<QString>("matched");
|
||||
|
||||
QTest::newRow("normal") << QRegularExpression("(test|foo)") << "test _ foo _ test _ Foo";
|
||||
QTest::newRow("normal2") << QRegularExpression("(Test|Foo)") << "test _ foo _ test _ Foo";
|
||||
QTest::newRow("case insensitive") << QRegularExpression("(test|foo)", QRegularExpression::CaseInsensitiveOption) << "test _ foo _ test _ Foo";
|
||||
QTest::newRow("case insensitive2") << QRegularExpression("(Test|Foo)", QRegularExpression::CaseInsensitiveOption) << "test _ foo _ test _ Foo";
|
||||
QTest::newRow("b(a*)(b*)") << QRegularExpression("b(a*)(b*)", QRegularExpression::CaseInsensitiveOption) << "aaabbBbaAabaAaababaaabbaaab";
|
||||
QTest::newRow("greedy") << QRegularExpression("a*(a*)", QRegularExpression::CaseInsensitiveOption) << "aaaabaaba";
|
||||
QTest::newRow("wildcard") << QRegularExpression(".*\\.txt") << "file.txt";
|
||||
QTest::newRow("wildcard 2") << QRegularExpression("a.b\\.txt") << "ab.txt abb.rtc acb.txt";
|
||||
QTest::newRow("slash") << QRegularExpression("g/.*/s", QRegularExpression::CaseInsensitiveOption) << "string/string/string";
|
||||
QTest::newRow("slash2") << QRegularExpression("g / .* / s", QRegularExpression::CaseInsensitiveOption) << "string / string / string";
|
||||
QTest::newRow("fixed") << QRegularExpression("a\\*aa\\.a\\(ba\\)\\*a\\\\ba", QRegularExpression::CaseInsensitiveOption) << "aa*aa.a(ba)*a\\ba";
|
||||
QTest::newRow("fixed insensitive") << QRegularExpression("A\\*A", QRegularExpression::CaseInsensitiveOption) << "a*A A*a A*A a*a";
|
||||
QTest::newRow("fixed sensitive") << QRegularExpression("A\\*A") << "a*A A*a A*A a*a";
|
||||
QTest::newRow("html") << QRegularExpression("<b>(.*)</b>") << "<b>bold</b><i>italic</i><b>bold</b>";
|
||||
QTest::newRow("html minimal") << QRegularExpression("^<b>(.*)</b>$") << "<b>bold</b><i>italic</i><b>bold</b>";
|
||||
QTest::newRow("aaa") << QRegularExpression("a{2,5}") << "aAaAaaaaaAa";
|
||||
QTest::newRow("aaa minimal") << QRegularExpression("^a{2,5}$") << "aAaAaaaaaAa";
|
||||
QTest::newRow("minimal") << QRegularExpression("^.*\\} [*8]$") << "}?} ?} *";
|
||||
QTest::newRow(".? minimal") << QRegularExpression("^.?$") << ".?";
|
||||
QTest::newRow(".+ minimal") << QRegularExpression("^.+$") << ".+";
|
||||
QTest::newRow("[.?] minimal") << QRegularExpression("^[.?]$") << ".?";
|
||||
QTest::newRow("[.+] minimal") << QRegularExpression("^[.+]$") << ".+";
|
||||
}
|
||||
|
||||
void tst_QJSEngine::qRegularExpressionImport()
|
||||
{
|
||||
QFETCH(QRegularExpression, rx);
|
||||
QFETCH(QString, string);
|
||||
|
||||
QJSEngine eng;
|
||||
QJSValue rexp;
|
||||
rexp = eng.toScriptValue(rx);
|
||||
|
||||
QCOMPARE(rexp.isRegExp(), true);
|
||||
QCOMPARE(rexp.isCallable(), false);
|
||||
|
||||
QJSValue func = eng.evaluate("(function(string, regexp) { return string.match(regexp); })");
|
||||
QJSValue result = func.call(QJSValueList() << string << rexp);
|
||||
|
||||
const QRegularExpressionMatch match = rx.match(string);
|
||||
for (int i = 0; i <= match.lastCapturedIndex(); i++)
|
||||
QCOMPARE(result.property(i).toString(), match.captured(i));
|
||||
}
|
||||
|
||||
// QScriptValue::toDateTime() returns a local time, whereas JS dates
|
||||
// are always stored as UTC. Qt Script must respect the current time
|
||||
// zone, and correctly adjust for daylight saving time that may be in
|
||||
|
|
|
@ -1027,6 +1027,20 @@ void tst_QJSValue::toVariant()
|
|||
QJSValue rxObject = eng.toScriptValue(rx);
|
||||
QVERIFY(rxObject.isRegExp());
|
||||
QVariant var = rxObject.toVariant();
|
||||
|
||||
// We can't roundtrip a QRegExp this way, as toVariant() has no information on whether we
|
||||
// want QRegExp or QRegularExpression. It will always create a QRegularExpression.
|
||||
QCOMPARE(var.type(), QMetaType::QRegularExpression);
|
||||
QRegularExpression result = var.toRegularExpression();
|
||||
QCOMPARE(result.pattern(), rx.pattern());
|
||||
QCOMPARE(result.patternOptions() & QRegularExpression::CaseInsensitiveOption, 0);
|
||||
}
|
||||
|
||||
{
|
||||
QRegularExpression rx = QRegularExpression("[0-9a-z]+");
|
||||
QJSValue rxObject = eng.toScriptValue(rx);
|
||||
QVERIFY(rxObject.isRegExp());
|
||||
QVariant var = rxObject.toVariant();
|
||||
QCOMPARE(var, QVariant(rx));
|
||||
}
|
||||
|
||||
|
@ -1194,6 +1208,32 @@ void tst_QJSValue::toRegExp()
|
|||
QVERIFY(qjsvalue_cast<QRegExp>(eng.toScriptValue(QVariant())).isEmpty());
|
||||
}
|
||||
|
||||
void tst_QJSValue::toRegularExpression()
|
||||
{
|
||||
QJSEngine eng;
|
||||
{
|
||||
QRegularExpression rx = qjsvalue_cast<QRegularExpression>(eng.evaluate("/foo/"));
|
||||
QVERIFY(rx.isValid());
|
||||
QCOMPARE(rx.pattern(), QString::fromLatin1("foo"));
|
||||
QVERIFY(!(rx.patternOptions() & QRegularExpression::CaseInsensitiveOption));
|
||||
}
|
||||
{
|
||||
QRegularExpression rx = qjsvalue_cast<QRegularExpression>(eng.evaluate("/bar/gi"));
|
||||
QVERIFY(rx.isValid());
|
||||
QCOMPARE(rx.pattern(), QString::fromLatin1("bar"));
|
||||
QVERIFY(rx.patternOptions() & QRegularExpression::CaseInsensitiveOption);
|
||||
}
|
||||
|
||||
QVERIFY(qjsvalue_cast<QRegularExpression>(eng.evaluate("[]")).pattern().isEmpty());
|
||||
QVERIFY(qjsvalue_cast<QRegularExpression>(eng.evaluate("{}")).pattern().isEmpty());
|
||||
QVERIFY(qjsvalue_cast<QRegularExpression>(eng.globalObject()).pattern().isEmpty());
|
||||
QVERIFY(qjsvalue_cast<QRegularExpression>(QJSValue()).pattern().isEmpty());
|
||||
QVERIFY(qjsvalue_cast<QRegularExpression>(QJSValue(123)).pattern().isEmpty());
|
||||
QVERIFY(qjsvalue_cast<QRegularExpression>(QJSValue(false)).pattern().isEmpty());
|
||||
QVERIFY(qjsvalue_cast<QRegularExpression>(eng.evaluate("null")).pattern().isEmpty());
|
||||
QVERIFY(qjsvalue_cast<QRegularExpression>(eng.toScriptValue(QVariant())).pattern().isEmpty());
|
||||
}
|
||||
|
||||
void tst_QJSValue::isArray_data()
|
||||
{
|
||||
newEngine();
|
||||
|
|
|
@ -76,6 +76,7 @@ private slots:
|
|||
void toQObject();
|
||||
void toDateTime();
|
||||
void toRegExp();
|
||||
void toRegularExpression();
|
||||
void isArray_data();
|
||||
void isArray();
|
||||
void isDate();
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import Qt.test 1.0
|
||||
|
||||
MyQmlObject{
|
||||
id: obj
|
||||
objectName: "obj"
|
||||
regularExpression: "[a-zA-z]"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import Qt.test 1.0
|
||||
|
||||
MyQmlObject{
|
||||
id: obj
|
||||
objectName: "obj"
|
||||
regularExpression: /[a-zA-z]/
|
||||
}
|
|
@ -33,6 +33,7 @@
|
|||
#include <QtQml/qqmlexpression.h>
|
||||
#include <QtCore/qpoint.h>
|
||||
#include <QtCore/qsize.h>
|
||||
#include <QtCore/qregularexpression.h>
|
||||
#include <QtQml/qqmllist.h>
|
||||
#include <QtCore/qrect.h>
|
||||
#include <QtGui/qmatrix.h>
|
||||
|
@ -101,6 +102,7 @@ class MyQmlObject : public QObject
|
|||
Q_PROPERTY(QQmlListProperty<QObject> objectListProperty READ objectListProperty CONSTANT)
|
||||
Q_PROPERTY(int resettableProperty READ resettableProperty WRITE setResettableProperty RESET resetProperty)
|
||||
Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp)
|
||||
Q_PROPERTY(QRegularExpression regularExpression READ regularExpression WRITE setRegularExpression)
|
||||
Q_PROPERTY(int nonscriptable READ nonscriptable WRITE setNonscriptable SCRIPTABLE false)
|
||||
Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty NOTIFY intChanged)
|
||||
Q_PROPERTY(QJSValue qjsvalue READ qjsvalue WRITE setQJSValue NOTIFY qjsvalueChanged)
|
||||
|
@ -170,6 +172,12 @@ public:
|
|||
QRegExp regExp() { return m_regExp; }
|
||||
void setRegExp(const QRegExp ®Exp) { m_regExp = regExp; }
|
||||
|
||||
QRegularExpression regularExpression() { return m_regularExpression; }
|
||||
void setRegularExpression(const QRegularExpression ®ularExpression)
|
||||
{
|
||||
m_regularExpression = regularExpression;
|
||||
}
|
||||
|
||||
int console() const { return 11; }
|
||||
|
||||
int nonscriptable() const { return 0; }
|
||||
|
@ -270,6 +278,7 @@ private:
|
|||
int m_value;
|
||||
int m_resetProperty;
|
||||
QRegExp m_regExp;
|
||||
QRegularExpression m_regularExpression;
|
||||
QVariant m_variant;
|
||||
QJSValue m_qjsvalue;
|
||||
int m_intProperty;
|
||||
|
|
|
@ -2418,6 +2418,13 @@ void tst_qqmlecmascript::regExpBug()
|
|||
delete object;
|
||||
}
|
||||
|
||||
{
|
||||
QQmlComponent component(&engine, testFileUrl("regularExpression.qml"));
|
||||
QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
|
||||
QVERIFY(!object.isNull());
|
||||
QCOMPARE(object->regularExpression().pattern(), QLatin1String("[a-zA-z]"));
|
||||
}
|
||||
|
||||
//QTBUG-23068
|
||||
{
|
||||
QString err = QString(QLatin1String("%1:6 Invalid property assignment: regular expression expected; use /pattern/ syntax\n")).arg(testFileUrl("regExp.2.qml").toString());
|
||||
|
@ -2427,6 +2434,18 @@ void tst_qqmlecmascript::regExpBug()
|
|||
QVERIFY(!object);
|
||||
QCOMPARE(component.errorString(), err);
|
||||
}
|
||||
|
||||
{
|
||||
const QString err = QString::fromLatin1("%1:6 Invalid property assignment: "
|
||||
"regular expression expected; "
|
||||
"use /pattern/ syntax\n")
|
||||
.arg(testFileUrl("regularExpression.2.qml").toString());
|
||||
QQmlComponent component(&engine, testFileUrl("regularExpression.2.qml"));
|
||||
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
|
||||
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
|
||||
QVERIFY(!object);
|
||||
QCOMPARE(component.errorString(), err);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool evaluate_error(QV4::ExecutionEngine *v4, const QV4::Value &o, const char *source)
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <QtCore/qtimer.h>
|
||||
#include <QtCore/qdir.h>
|
||||
#include <QtCore/qfileinfo.h>
|
||||
#include <QtCore/qregularexpression.h>
|
||||
#include <QtQml/qjsengine.h>
|
||||
|
||||
#include <QtQml/qqmlcomponent.h>
|
||||
|
@ -118,7 +119,18 @@ void tst_QQuickWorkerScript::messaging()
|
|||
QVariant response = mo->property(mo->indexOfProperty("response")).read(worker).value<QVariant>();
|
||||
if (response.userType() == qMetaTypeId<QJSValue>())
|
||||
response = response.value<QJSValue>().toVariant();
|
||||
QCOMPARE(response, value);
|
||||
|
||||
if (value.type() == QMetaType::QRegExp && response.type() == QMetaType::QRegularExpression) {
|
||||
// toVariant() doesn't know if we want QRegExp or QRegularExpression. It always creates
|
||||
// a QRegularExpression from a JavaScript regular expression.
|
||||
const QRegularExpression responseRegExp = response.toRegularExpression();
|
||||
const QRegExp valueRegExp = value.toRegExp();
|
||||
QCOMPARE(responseRegExp.pattern(), valueRegExp.pattern());
|
||||
QCOMPARE(bool(responseRegExp.patternOptions() & QRegularExpression::CaseInsensitiveOption),
|
||||
bool(valueRegExp.caseSensitivity() == Qt::CaseInsensitive));
|
||||
} else {
|
||||
QCOMPARE(response, value);
|
||||
}
|
||||
|
||||
qApp->processEvents();
|
||||
delete worker;
|
||||
|
@ -135,10 +147,10 @@ void tst_QQuickWorkerScript::messaging_data()
|
|||
QTest::newRow("string") << qVariantFromValue(QString("More cheeeese, Gromit!"));
|
||||
QTest::newRow("variant list") << qVariantFromValue((QVariantList() << "a" << "b" << "c"));
|
||||
QTest::newRow("date time") << qVariantFromValue(QDateTime::currentDateTime());
|
||||
#ifndef QT_NO_REGEXP
|
||||
// Qt Script's QScriptValue -> QRegExp uses RegExp2 pattern syntax
|
||||
QTest::newRow("regexp") << qVariantFromValue(QRegExp("^\\d\\d?$", Qt::CaseInsensitive, QRegExp::RegExp2));
|
||||
#endif
|
||||
QTest::newRow("regexp") << qVariantFromValue(QRegExp("^\\d\\d?$", Qt::CaseInsensitive,
|
||||
QRegExp::RegExp2));
|
||||
QTest::newRow("regularexpression") << qVariantFromValue(QRegularExpression(
|
||||
"^\\d\\d?$", QRegularExpression::CaseInsensitiveOption));
|
||||
}
|
||||
|
||||
void tst_QQuickWorkerScript::messaging_sendQObjectList()
|
||||
|
|
Loading…
Reference in New Issue