aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-08-08 13:55:17 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2018-08-15 14:24:26 +0000
commitcda5885efab0b9905260e0d48013d1d10644eb29 (patch)
treea243e06a5e8a486999623c1425e035864670e1b9
parenta1964f0b8e0569ef9ab754e2ec4c4d0559bc7681 (diff)
Improve RegExp.prototype[Symbol.match] implementation
Change-Id: Id632a4f4648f68f3b46d31f84e4ee05c86391f3e Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/jsruntime/qv4engine.cpp5
-rw-r--r--src/qml/jsruntime/qv4engine_p.h10
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp67
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations18
4 files changed, 70 insertions, 30 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index f7189894b2..444d12d118 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -286,6 +286,11 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsStrings[String_next] = newIdentifier(QStringLiteral("next"));
jsStrings[String_done] = newIdentifier(QStringLiteral("done"));
jsStrings[String_return] = newIdentifier(QStringLiteral("return"));
+ jsStrings[String_global] = newIdentifier(QStringLiteral("global"));
+ jsStrings[String_ignoreCase] = newIdentifier(QStringLiteral("ignoreCase"));
+ jsStrings[String_multiline] = newIdentifier(QStringLiteral("multiline"));
+ jsStrings[String_unicode] = newIdentifier(QStringLiteral("unicode"));
+ jsStrings[String_sticky] = newIdentifier(QStringLiteral("sticky"));
jsSymbols[Symbol_hasInstance] = Symbol::create(this, QStringLiteral("@Symbol.hasInstance"));
jsSymbols[Symbol_isConcatSpreadable] = Symbol::create(this, QStringLiteral("@Symbol.isConcatSpreadable"));
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index e605be9901..3a782ae097 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -322,6 +322,11 @@ public:
String_next,
String_done,
String_return,
+ String_global,
+ String_ignoreCase,
+ String_multiline,
+ String_unicode,
+ String_sticky,
NJSStrings
};
@@ -385,6 +390,11 @@ public:
String *id_next() const { return reinterpret_cast<String *>(jsStrings + String_next); }
String *id_done() const { return reinterpret_cast<String *>(jsStrings + String_done); }
String *id_return() const { return reinterpret_cast<String *>(jsStrings + String_return); }
+ String *id_global() const { return reinterpret_cast<String *>(jsStrings + String_global); }
+ String *id_ignoreCase() const { return reinterpret_cast<String *>(jsStrings + String_ignoreCase); }
+ String *id_multiline() const { return reinterpret_cast<String *>(jsStrings + String_multiline); }
+ String *id_unicode() const { return reinterpret_cast<String *>(jsStrings + String_unicode); }
+ String *id_sticky() const { return reinterpret_cast<String *>(jsStrings + String_sticky); }
Symbol *symbol_hasInstance() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_hasInstance); }
Symbol *symbol_isConcatSpreadable() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_isConcatSpreadable); }
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index b54e73b85c..8d457352d7 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -337,16 +337,16 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor)
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);
+ defineAccessorProperty(scope.engine->id_global(), method_get_global, nullptr);
+ defineAccessorProperty(scope.engine->id_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(scope.engine->id_multiline(), method_get_multiline, nullptr);
defineAccessorProperty(QStringLiteral("source"), method_get_source, nullptr);
- defineAccessorProperty(QStringLiteral("sticky"), method_get_sticky, nullptr);
+ defineAccessorProperty(scope.engine->id_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);
+ defineAccessorProperty(scope.engine->id_unicode(), method_get_unicode, nullptr);
// another web extension
defineDefaultProperty(QStringLiteral("compile"), method_compile, 2);
@@ -439,28 +439,27 @@ ReturnedValue RegExpPrototype::method_get_flags(const FunctionObject *f, const V
QString result;
ScopedValue v(scope);
- ScopedString key(scope);
- v = o->get((key = scope.engine->newString(QStringLiteral("global"))));
+ v = o->get(scope.engine->id_global());
if (scope.hasException())
return Encode::undefined();
if (v->toBoolean())
result += QLatin1Char('g');
- v = o->get((key = scope.engine->newString(QStringLiteral("ignoreCase"))));
+ v = o->get(scope.engine->id_ignoreCase());
if (scope.hasException())
return Encode::undefined();
if (v->toBoolean())
result += QLatin1Char('i');
- v = o->get((key = scope.engine->newString(QStringLiteral("multiline"))));
+ v = o->get(scope.engine->id_multiline());
if (scope.hasException())
return Encode::undefined();
if (v->toBoolean())
result += QLatin1Char('m');
- v = o->get((key = scope.engine->newString(QStringLiteral("unicode"))));
+ v = o->get(scope.engine->id_unicode());
if (scope.hasException())
return Encode::undefined();
if (v->toBoolean())
result += QLatin1Char('u');
- v = o->get((key = scope.engine->newString(QStringLiteral("sticky"))));
+ v = o->get(scope.engine->id_sticky());
if (scope.hasException())
return Encode::undefined();
if (v->toBoolean())
@@ -499,14 +498,52 @@ ReturnedValue RegExpPrototype::method_match(const FunctionObject *f, const Value
ScopedString s(scope, (argc ? argv[0] : Primitive::undefinedValue()).toString(scope.engine));
if (scope.hasException())
return Encode::undefined();
- ScopedString key(scope, scope.engine->newString(QStringLiteral("global")));
- bool global = ScopedValue(scope, rx->get(key))->toBoolean();
+ bool global = ScopedValue(scope, rx->get(scope.engine->id_global()))->toBoolean();
if (!global)
return exec(scope.engine, rx, s);
- // ####
- return scope.engine->throwTypeError();
+ bool unicode = ScopedValue(scope, rx->get(scope.engine->id_unicode()))->toBoolean();
+
+ rx->put(scope.engine->id_lastIndex(), Primitive::fromInt32(0));
+ ScopedArrayObject a(scope, scope.engine->newArrayObject());
+ uint n = 0;
+
+ ScopedValue result(scope);
+ ScopedValue match(scope);
+ ScopedString matchString(scope);
+ ScopedValue v(scope);
+ while (1) {
+ result = exec(scope.engine, rx, s);
+ if (scope.hasException())
+ return Encode::undefined();
+ if (result->isNull()) {
+ if (!n)
+ return Encode::null();
+ return a->asReturnedValue();
+ }
+ Q_ASSERT(result->isObject());
+ match = static_cast<Object &>(*result).getIndexed(0);
+ matchString = match->toString(scope.engine);
+ if (scope.hasException())
+ return Encode::undefined();
+ a->push_back(matchString);
+ if (matchString->d()->length() == 0) {
+ v = rx->get(scope.engine->id_lastIndex());
+ int lastIndex = v->toLength();
+ if (unicode) {
+ QString str = s->toQString();
+ if (lastIndex < str.length() - 1 &&
+ str.at(lastIndex).isHighSurrogate() &&
+ str.at(lastIndex + 1).isLowSurrogate())
+ ++lastIndex;
+ }
+ ++lastIndex;
+ if (!rx->put(scope.engine->id_lastIndex(), Primitive::fromInt32(lastIndex)))
+ return scope.engine->throwTypeError();
+ }
+ ++n;
+ }
}
ReturnedValue RegExpPrototype::method_get_multiline(const FunctionObject *f, const Value *thisObject, const Value *, int)
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index 85e2e72ac7..5fb6bb1cd9 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -709,26 +709,14 @@ built-ins/RegExp/from-regexp-like.js fails
built-ins/RegExp/proto-from-ctor-realm.js fails
built-ins/RegExp/prototype/15.10.6.js fails
built-ins/RegExp/prototype/Symbol.match/builtin-coerce-lastindex.js fails
-built-ins/RegExp/prototype/Symbol.match/builtin-failure-g-set-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-failure-g-set-lastindex-err.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-success-g-set-lastindex-err.js fails
built-ins/RegExp/prototype/Symbol.match/builtin-success-u-return-val-groups.js fails
built-ins/RegExp/prototype/Symbol.match/builtin-failure-y-set-lastindex-err.js fails
built-ins/RegExp/prototype/Symbol.match/builtin-failure-y-set-lastindex.js fails
built-ins/RegExp/prototype/Symbol.match/builtin-success-y-set-lastindex-err.js fails
built-ins/RegExp/prototype/Symbol.match/builtin-success-y-set-lastindex.js fails
-built-ins/RegExp/prototype/Symbol.match/coerce-global.js fails
-built-ins/RegExp/prototype/Symbol.match/g-coerce-result-err.js fails
-built-ins/RegExp/prototype/Symbol.match/g-get-exec-err.js fails
-built-ins/RegExp/prototype/Symbol.match/g-get-result-err.js fails
-built-ins/RegExp/prototype/Symbol.match/g-init-lastindex.js fails
-built-ins/RegExp/prototype/Symbol.match/g-match-empty-advance-lastindex.js fails
-built-ins/RegExp/prototype/Symbol.match/g-match-empty-coerce-lastindex-err.js fails
-built-ins/RegExp/prototype/Symbol.match/g-match-no-coerce-lastindex.js fails
-built-ins/RegExp/prototype/Symbol.match/g-match-no-set-lastindex.js fails
-built-ins/RegExp/prototype/Symbol.match/g-success-return-val.js fails
-built-ins/RegExp/prototype/Symbol.match/g-zero-matches.js fails
-built-ins/RegExp/prototype/Symbol.match/get-unicode-error.js fails
-built-ins/RegExp/prototype/Symbol.match/u-advance-after-empty.js fails
-built-ins/RegExp/prototype/Symbol.match/y-fail-global-return.js fails
+built-ins/RegExp/prototype/Symbol.match/g-init-lastindex-err.js fails
built-ins/RegExp/prototype/Symbol.match/y-fail-lastindex-no-write.js fails
built-ins/RegExp/prototype/Symbol.match/y-init-lastindex.js fails
built-ins/RegExp/prototype/Symbol.match/y-set-lastindex.js fails