aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4regexpobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4regexpobject.cpp')
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp231
1 files changed, 167 insertions, 64 deletions
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index cff8223942..b54e73b85c 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -68,7 +68,7 @@ void Heap::RegExpObject::init()
Object::init();
Scope scope(internalClass->engine);
Scoped<QV4::RegExpObject> o(scope, this);
- value.set(scope.engine, QV4::RegExp::create(scope.engine, QString(), false, false));
+ value.set(scope.engine, QV4::RegExp::create(scope.engine, QString(), CompiledData::RegExp::RegExp_NoFlags));
o->initProperties();
}
@@ -128,8 +128,8 @@ void Heap::RegExpObject::init(const QRegExp &re)
Scope scope(internalClass->engine);
Scoped<QV4::RegExpObject> o(scope, this);
- o->d()->value.set(scope.engine,
- QV4::RegExp::create(scope.engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false));
+ uint flags = (re.caseSensitivity() == Qt::CaseInsensitive ? CompiledData::RegExp::RegExp_IgnoreCase : CompiledData::RegExp::RegExp_NoFlags);
+ o->d()->value.set(scope.engine, QV4::RegExp::create(scope.engine, pattern, flags));
o->initProperties();
}
@@ -139,20 +139,6 @@ void RegExpObject::initProperties()
setProperty(Index_LastIndex, Primitive::fromInt32(0));
Q_ASSERT(value());
-
- QString p = *value()->pattern;
- if (p.isEmpty()) {
- p = QStringLiteral("(?:)");
- } else {
- // escape certain parts, see ch. 15.10.4
- p.replace('/', QLatin1String("\\/"));
- }
-
- setProperty(Index_Source, engine()->newString(p));
- setProperty(Index_Global, Primitive::fromBoolean(global()));
- setProperty(Index_IgnoreCase, Primitive::fromBoolean(value()->ignoreCase));
- setProperty(Index_Multiline, Primitive::fromBoolean(value()->multiLine));
- setProperty(Index_Unicode, Primitive::fromBoolean(value()->unicode));
}
// Converts a JS RegExp to a QRegExp.
@@ -160,20 +146,20 @@ void RegExpObject::initProperties()
// have different semantics/flags, but we try to do our best.
QRegExp RegExpObject::toQRegExp() const
{
- Qt::CaseSensitivity caseSensitivity = value()->ignoreCase ? Qt::CaseInsensitive : Qt::CaseSensitive;
+ Qt::CaseSensitivity caseSensitivity = (value()->flags & CompiledData::RegExp::RegExp_IgnoreCase) ? Qt::CaseInsensitive : Qt::CaseSensitive;
return QRegExp(*value()->pattern, caseSensitivity, QRegExp::RegExp2);
}
QString RegExpObject::toString() const
{
- QString result = QLatin1Char('/') + source() + QLatin1Char('/');
- if (global())
- result += QLatin1Char('g');
- if (value()->ignoreCase)
- result += QLatin1Char('i');
- if (value()->multiLine)
- result += QLatin1Char('m');
- return result;
+ QString p = *value()->pattern;
+ if (p.isEmpty()) {
+ p = QStringLiteral("(?:)");
+ } else {
+ // escape certain parts, see ch. 15.10.4
+ p.replace('/', QLatin1String("\\/"));
+ }
+ return p;
}
QString RegExpObject::source() const
@@ -186,16 +172,7 @@ QString RegExpObject::source() const
uint RegExpObject::flags() const
{
- uint f = 0;
- if (global())
- f |= QV4::RegExpObject::RegExp_Global;
- if (value()->ignoreCase)
- f |= QV4::RegExpObject::RegExp_IgnoreCase;
- if (value()->multiLine)
- f |= QV4::RegExpObject::RegExp_Multiline;
- if (value()->unicode)
- f |= QV4::RegExpObject::RegExp_Unicode;
- return f;
+ return d()->value->flags;
}
ReturnedValue RegExpObject::builtinExec(ExecutionEngine *engine, const String *str)
@@ -286,28 +263,30 @@ ReturnedValue RegExpCtor::virtualCallAsConstructor(const FunctionObject *fo, con
if (scope.hasException())
return Encode::undefined();
- bool global = false;
- bool ignoreCase = false;
- bool multiLine = false;
+ uint flags = CompiledData::RegExp::RegExp_NoFlags;
if (!f->isUndefined()) {
ScopedString s(scope, f->toString(scope.engine));
if (scope.hasException())
return Encode::undefined();
QString str = s->toQString();
for (int i = 0; i < str.length(); ++i) {
- if (str.at(i) == QLatin1Char('g') && !global) {
- global = true;
- } else if (str.at(i) == QLatin1Char('i') && !ignoreCase) {
- ignoreCase = true;
- } else if (str.at(i) == QLatin1Char('m') && !multiLine) {
- multiLine = true;
+ if (str.at(i) == QLatin1Char('g') && !(flags & CompiledData::RegExp::RegExp_Global)) {
+ flags |= CompiledData::RegExp::RegExp_Global;
+ } else if (str.at(i) == QLatin1Char('i') && !(flags & CompiledData::RegExp::RegExp_IgnoreCase)) {
+ flags |= CompiledData::RegExp::RegExp_IgnoreCase;
+ } else if (str.at(i) == QLatin1Char('m') && !(flags & CompiledData::RegExp::RegExp_Multiline)) {
+ flags |= CompiledData::RegExp::RegExp_Multiline;
+ } else if (str.at(i) == QLatin1Char('u') && !(flags & CompiledData::RegExp::RegExp_Unicode)) {
+ flags |= CompiledData::RegExp::RegExp_Unicode;
+ } else if (str.at(i) == QLatin1Char('y') && !(flags & CompiledData::RegExp::RegExp_Sticky)) {
+ flags |= CompiledData::RegExp::RegExp_Sticky;
} else {
return scope.engine->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor"));
}
}
}
- Scoped<RegExp> regexp(scope, RegExp::create(scope.engine, pattern, ignoreCase, multiLine, global));
+ Scoped<RegExp> regexp(scope, RegExp::create(scope.engine, pattern, flags));
if (!regexp->isValid()) {
return scope.engine->throwSyntaxError(QStringLiteral("Invalid regular expression"));
}
@@ -357,11 +336,20 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor)
ctor->defineAccessorProperty(QStringLiteral("$'"), method_get_rightContext, nullptr);
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
+ defineAccessorProperty(QStringLiteral("flags"), method_get_flags, nullptr);
+ defineAccessorProperty(QStringLiteral("global"), method_get_global, nullptr);
+ defineAccessorProperty(QStringLiteral("ignoreCase"), method_get_ignoreCase, nullptr);
defineDefaultProperty(QStringLiteral("exec"), method_exec, 1);
+ defineDefaultProperty(engine->symbol_match(), method_match, 1);
+ defineAccessorProperty(QStringLiteral("multiline"), method_get_multiline, nullptr);
+ defineAccessorProperty(QStringLiteral("source"), method_get_source, nullptr);
+ defineAccessorProperty(QStringLiteral("sticky"), method_get_sticky, nullptr);
defineDefaultProperty(QStringLiteral("test"), method_test, 1);
defineDefaultProperty(engine->id_toString(), method_toString, 0);
+ defineAccessorProperty(QStringLiteral("unicode"), method_get_unicode, nullptr);
+
+ // another web extension
defineDefaultProperty(QStringLiteral("compile"), method_compile, 2);
- defineDefaultProperty(engine->symbol_match(), method_match, 1);
}
/* used by String.match */
@@ -442,33 +430,64 @@ ReturnedValue RegExpPrototype::method_exec(const FunctionObject *b, const Value
return r->builtinExec(scope.engine, str);
}
-ReturnedValue RegExpPrototype::method_test(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue RegExpPrototype::method_get_flags(const FunctionObject *f, const Value *thisObject, const Value *, int)
{
- Value res = Value::fromReturnedValue(method_exec(b, thisObject, argv, argc));
- return Encode(!res.isNull());
+ Scope scope(f);
+ ScopedObject o(scope, thisObject);
+ if (!o)
+ return scope.engine->throwTypeError();
+
+ QString result;
+ ScopedValue v(scope);
+ ScopedString key(scope);
+ v = o->get((key = scope.engine->newString(QStringLiteral("global"))));
+ if (scope.hasException())
+ return Encode::undefined();
+ if (v->toBoolean())
+ result += QLatin1Char('g');
+ v = o->get((key = scope.engine->newString(QStringLiteral("ignoreCase"))));
+ if (scope.hasException())
+ return Encode::undefined();
+ if (v->toBoolean())
+ result += QLatin1Char('i');
+ v = o->get((key = scope.engine->newString(QStringLiteral("multiline"))));
+ if (scope.hasException())
+ return Encode::undefined();
+ if (v->toBoolean())
+ result += QLatin1Char('m');
+ v = o->get((key = scope.engine->newString(QStringLiteral("unicode"))));
+ if (scope.hasException())
+ return Encode::undefined();
+ if (v->toBoolean())
+ result += QLatin1Char('u');
+ v = o->get((key = scope.engine->newString(QStringLiteral("sticky"))));
+ if (scope.hasException())
+ return Encode::undefined();
+ if (v->toBoolean())
+ result += QLatin1Char('y');
+ return scope.engine->newString(result)->asReturnedValue();
}
-ReturnedValue RegExpPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
+ReturnedValue RegExpPrototype::method_get_global(const FunctionObject *f, const Value *thisObject, const Value *, int)
{
- ExecutionEngine *v4 = b->engine();
- const RegExpObject *r = thisObject->as<RegExpObject>();
- if (!r)
- return v4->throwTypeError();
+ Scope scope(f);
+ Scoped<RegExpObject> re(scope, thisObject);
+ if (!re)
+ return scope.engine->throwTypeError();
- return Encode(v4->newString(r->toString()));
+ bool b = re->value()->flags & CompiledData::RegExp::RegExp_Global;
+ return Encode(b);
}
-ReturnedValue RegExpPrototype::method_compile(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue RegExpPrototype::method_get_ignoreCase(const FunctionObject *f, const Value *thisObject, const Value *, int)
{
- Scope scope(b);
- Scoped<RegExpObject> r(scope, thisObject->as<RegExpObject>());
- if (!r)
+ Scope scope(f);
+ Scoped<RegExpObject> re(scope, thisObject);
+ if (!re)
return scope.engine->throwTypeError();
- Scoped<RegExpObject> re(scope, scope.engine->regExpCtor()->callAsConstructor(argv, argc));
-
- r->d()->value.set(scope.engine, re->value());
- return Encode::undefined();
+ bool b = re->value()->flags & CompiledData::RegExp::RegExp_IgnoreCase;
+ return Encode(b);
}
ReturnedValue RegExpPrototype::method_match(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
@@ -490,6 +509,90 @@ ReturnedValue RegExpPrototype::method_match(const FunctionObject *f, const Value
return scope.engine->throwTypeError();
}
+ReturnedValue RegExpPrototype::method_get_multiline(const FunctionObject *f, const Value *thisObject, const Value *, int)
+{
+ Scope scope(f);
+ Scoped<RegExpObject> re(scope, thisObject);
+ if (!re)
+ return scope.engine->throwTypeError();
+
+ bool b = re->value()->flags & CompiledData::RegExp::RegExp_Multiline;
+ return Encode(b);
+}
+
+ReturnedValue RegExpPrototype::method_get_source(const FunctionObject *f, const Value *thisObject, const Value *, int)
+{
+ Scope scope(f);
+ Scoped<RegExpObject> re(scope, thisObject);
+ if (!re)
+ return scope.engine->throwTypeError();
+
+ return scope.engine->newString(re->toString())->asReturnedValue();
+}
+
+ReturnedValue RegExpPrototype::method_get_sticky(const FunctionObject *f, const Value *thisObject, const Value *, int)
+{
+ Scope scope(f);
+ Scoped<RegExpObject> re(scope, thisObject);
+ if (!re)
+ return scope.engine->throwTypeError();
+
+ bool b = re->value()->flags & CompiledData::RegExp::RegExp_Sticky;
+ return Encode(b);
+}
+
+ReturnedValue RegExpPrototype::method_test(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Value res = Value::fromReturnedValue(method_exec(b, thisObject, argv, argc));
+ return Encode(!res.isNull());
+}
+
+ReturnedValue RegExpPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ const Object *r = thisObject->as<Object>();
+ if (!r)
+ return scope.engine->throwTypeError();
+
+ ScopedString key(scope);
+ ScopedValue v(scope);
+ v = r->get((key = scope.engine->newString(QStringLiteral("source"))));
+ ScopedString source(scope, v->toString(scope.engine));
+ if (scope.hasException())
+ return Encode::undefined();
+ v = r->get((key = scope.engine->newString(QStringLiteral("flags"))));
+ ScopedString flags(scope, v->toString(scope.engine));
+ if (scope.hasException())
+ return Encode::undefined();
+
+ QString result = QLatin1Char('/') + source->toQString() + QLatin1Char('/') + flags->toQString();
+ return Encode(scope.engine->newString(result));
+}
+
+ReturnedValue RegExpPrototype::method_get_unicode(const FunctionObject *f, const Value *thisObject, const Value *, int)
+{
+ Scope scope(f);
+ Scoped<RegExpObject> re(scope, thisObject);
+ if (!re)
+ return scope.engine->throwTypeError();
+
+ bool b = re->value()->flags & CompiledData::RegExp::RegExp_Unicode;
+ return Encode(b);
+}
+
+ReturnedValue RegExpPrototype::method_compile(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ Scoped<RegExpObject> r(scope, thisObject->as<RegExpObject>());
+ if (!r)
+ return scope.engine->throwTypeError();
+
+ Scoped<RegExpObject> re(scope, scope.engine->regExpCtor()->callAsConstructor(argv, argc));
+
+ r->d()->value.set(scope.engine, re->value());
+ return Encode::undefined();
+}
+
template <uint index>
ReturnedValue RegExpPrototype::method_get_lastMatch_n(const FunctionObject *b, const Value *, const Value *, int)
{