diff options
-rw-r--r-- | src/qml/jsruntime/qv4regexpobject.cpp | 48 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4regexpobject_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4stringobject.cpp | 71 |
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) |