aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp48
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp71
3 files changed, 79 insertions, 42 deletions
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index db5551f99c..c3a4275cac 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -314,6 +314,52 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor)
defineDefaultProperty(QStringLiteral("compile"), method_compile, 2);
}
+/* used by String.match */
+ReturnedValue RegExpPrototype::execFirstMatch(const BuiltinFunction *b, CallData *callData)
+{
+ Scope scope(b);
+ Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>());
+ Q_ASSERT(r && r->global());
+
+ ScopedString str(scope, callData->args[0]);
+ Q_ASSERT(str);
+ QString s = str->toQString();
+
+ int offset = r->lastIndex();
+ if (offset < 0 || offset > s.length()) {
+ r->setLastIndex(0);
+ RETURN_RESULT(Encode::null());
+ }
+
+ Q_ALLOCA_VAR(uint, matchOffsets, r->value()->captureCount() * 2 * sizeof(uint));
+ const int result = Scoped<RegExp>(scope, r->value())->match(s, offset, matchOffsets);
+
+ RegExpCtor *regExpCtor = static_cast<RegExpCtor *>(scope.engine->regExpCtor());
+ regExpCtor->d()->clearLastMatch();
+
+ if (result == -1) {
+ r->setLastIndex(0);
+ RETURN_RESULT(Encode::null());
+ }
+
+ ReturnedValue retVal = Encode::undefined();
+ // return first match
+ if (r->value()->captureCount()) {
+ int start = matchOffsets[0];
+ int end = matchOffsets[1];
+ retVal = (start != -1) ? scope.engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined();
+ }
+
+ RegExpCtor::Data *dd = regExpCtor->d();
+ dd->lastInput.set(scope.engine, str->d());
+ dd->lastMatchStart = matchOffsets[0];
+ dd->lastMatchEnd = matchOffsets[1];
+
+ r->setLastIndex(matchOffsets[1]);
+
+ return retVal;
+}
+
ReturnedValue RegExpPrototype::method_exec(const BuiltinFunction *b, CallData *callData)
{
Scope scope(b);
@@ -336,7 +382,7 @@ ReturnedValue RegExpPrototype::method_exec(const BuiltinFunction *b, CallData *c
Q_ALLOCA_VAR(uint, matchOffsets, r->value()->captureCount() * 2 * sizeof(uint));
const int result = Scoped<RegExp>(scope, r->value())->match(s, offset, matchOffsets);
- Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor());
+ RegExpCtor *regExpCtor = static_cast<RegExpCtor *>(scope.engine->regExpCtor());
regExpCtor->d()->clearLastMatch();
if (result == -1) {
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index f04940255b..b808ec38cf 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -169,6 +169,8 @@ struct RegExpPrototype: RegExpObject
static ReturnedValue method_get_input(const BuiltinFunction *, CallData *callData);
static ReturnedValue method_get_leftContext(const BuiltinFunction *, CallData *callData);
static ReturnedValue method_get_rightContext(const BuiltinFunction *, CallData *callData);
+
+ static ReturnedValue execFirstMatch(const BuiltinFunction *b, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 66ad5e79d2..2fc05e4f56 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -402,67 +402,56 @@ ReturnedValue StringPrototype::method_localeCompare(const BuiltinFunction *b, Ca
ReturnedValue StringPrototype::method_match(const BuiltinFunction *b, CallData *callData)
{
ExecutionEngine *v4 = b->engine();
- if (callData->thisObject.isUndefined() || callData->thisObject.isNull())
+ if (callData->thisObject.isNullOrUndefined())
return v4->throwTypeError();
Scope scope(v4);
- ScopedString s(scope, callData->thisObject.toString(scope.engine));
-
- ScopedValue regexp(scope, callData->argument(0));
- Scoped<RegExpObject> rx(scope, regexp);
- if (!rx) {
- JSCall jsCall(scope, scope.engine->regExpCtor(), 1);
- jsCall->args[0] = regexp;
- rx = jsCall.callAsConstructor();
- }
+ callData->thisObject = callData->thisObject.toString(scope.engine);
+ if (v4->hasException)
+ return Encode::undefined();
- if (!rx)
- // ### CHECK
- return v4->throwTypeError();
+ if (!callData->argc)
+ callData->args[0] = Encode::undefined();
+ callData->argc = 1;
- bool global = rx->global();
+ if (!callData->args[0].as<RegExpObject>()) {
+ // convert args[0] to a regexp
+ callData->args[0] = RegExpCtor::construct(b, callData);
+ if (v4->hasException)
+ return Encode::undefined();
+ }
- // ### use the standard builtin function, not the one that might be redefined in the proto
- ScopedString execString(scope, scope.engine->newString(QStringLiteral("exec")));
- ScopedFunctionObject exec(scope, scope.engine->regExpPrototype()->get(execString));
+ bool global = static_cast<RegExpObject *>(&callData->args[0])->global();
- JSCall jsCall(scope, exec, 1);
- jsCall->thisObject = rx;
- jsCall->args[0] = s;
+ qSwap(callData->thisObject, callData->args[0]);
if (!global)
- return jsCall.call();
+ return RegExpPrototype::method_exec(b, callData);
- ScopedString lastIndex(scope, scope.engine->newString(QStringLiteral("lastIndex")));
- rx->put(lastIndex, ScopedValue(scope, Primitive::fromInt32(0)));
+ // rx is now in thisObject
+ RegExpObject *rx = static_cast<RegExpObject *>(&callData->thisObject);
+ rx->setLastIndex(0);
ScopedArrayObject a(scope, scope.engine->newArrayObject());
- double previousLastIndex = 0;
+ int previousLastIndex = 0;
uint n = 0;
- ScopedValue matchStr(scope);
- ScopedValue index(scope);
- ScopedValue result(scope);
while (1) {
- result = jsCall.call();
- if (result->isNull())
+ Value result = Primitive::fromReturnedValue(RegExpPrototype::execFirstMatch(b, callData));
+ if (result.isNull())
break;
- assert(result->isObject());
- index = rx->get(lastIndex, 0);
- double thisIndex = index->toInteger();
- if (previousLastIndex == thisIndex) {
- previousLastIndex = thisIndex + 1;
- rx->put(lastIndex, ScopedValue(scope, Primitive::fromDouble(previousLastIndex)));
+ int index = rx->lastIndex();
+ if (previousLastIndex == index) {
+ previousLastIndex = index + 1;
+ rx->setLastIndex(previousLastIndex);
} else {
- previousLastIndex = thisIndex;
+ previousLastIndex = index;
}
- matchStr = result->objectValue()->getIndexed(0);
- a->arraySet(n, matchStr);
+ a->arraySet(n, result);
++n;
}
if (!n)
- result = Encode::null();
+ return Encode::null();
else
- result = a.asReturnedValue();
- return result->asReturnedValue();
+ return a.asReturnedValue();
}
ReturnedValue StringPrototype::method_repeat(const BuiltinFunction *b, CallData *callData)