diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/qml/compiler/qv4compileddata.cpp | 16 | ||||
| -rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 8 | ||||
| -rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 2 | ||||
| -rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 17 | ||||
| -rw-r--r-- | src/qml/jsruntime/qv4regexp.cpp | 53 | ||||
| -rw-r--r-- | src/qml/jsruntime/qv4regexp_p.h | 35 | ||||
| -rw-r--r-- | src/qml/jsruntime/qv4regexpobject.cpp | 231 | ||||
| -rw-r--r-- | src/qml/jsruntime/qv4regexpobject_p.h | 26 | ||||
| -rw-r--r-- | src/qml/parser/qqmljslexer.cpp | 1 | ||||
| -rw-r--r-- | src/qml/parser/qqmljslexer_p.h | 3 |
10 files changed, 244 insertions, 148 deletions
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 798bfe921e..46034050e0 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -149,19 +149,9 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) memset(runtimeRegularExpressions, 0, data->regexpTableSize * sizeof(QV4::Value)); for (uint i = 0; i < data->regexpTableSize; ++i) { const CompiledData::RegExp *re = data->regexpAt(i); - bool global = false; - bool multiline = false; - bool ignoreCase = false; - bool unicode = false; - if (re->flags & CompiledData::RegExp::RegExp_Global) - global = true; - if (re->flags & CompiledData::RegExp::RegExp_IgnoreCase) - ignoreCase = true; - if (re->flags & CompiledData::RegExp::RegExp_Multiline) - multiline = true; - if (re->flags & CompiledData::RegExp::RegExp_Unicode) - unicode = true; - runtimeRegularExpressions[i] = QV4::RegExp::create(engine, stringAt(re->stringIndex), ignoreCase, multiline, global, unicode); + uint f = re->flags; + const CompiledData::RegExp::Flags flags = static_cast<CompiledData::RegExp::Flags>(f); + runtimeRegularExpressions[i] = QV4::RegExp::create(engine, stringAt(re->stringIndex), flags); } if (data->lookupTableSize) { diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 4b0e6422bb..7581fe3fff 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -137,15 +137,17 @@ static_assert(sizeof(Location) == 4, "Location structure needs to have the expec struct RegExp { enum Flags : unsigned int { + RegExp_NoFlags = 0x0, RegExp_Global = 0x01, RegExp_IgnoreCase = 0x02, RegExp_Multiline = 0x04, - RegExp_Unicode = 0x08 + RegExp_Unicode = 0x08, + RegExp_Sticky = 0x10 }; union { quint32 _dummy; - quint32_le_bitfield<0, 4> flags; - quint32_le_bitfield<4, 28> stringIndex; + quint32_le_bitfield<0, 5> flags; + quint32_le_bitfield<5, 27> stringIndex; }; RegExp() : _dummy(0) { } diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 594ea32b51..4a726c366d 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -180,6 +180,8 @@ int QV4::Compiler::JSUnitGenerator::registerRegExp(QQmlJS::AST::RegExpLiteral *r re.flags |= CompiledData::RegExp::RegExp_Multiline; if (regexp->flags & QQmlJS::Lexer::RegExp_Unicode) re.flags |= CompiledData::RegExp::RegExp_Unicode; + if (regexp->flags & QQmlJS::Lexer::RegExp_Sticky) + re.flags |= CompiledData::RegExp::RegExp_Sticky; regexps.append(re); return regexps.size() - 1; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index dbe1441cfc..f7189894b2 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -369,16 +369,6 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) ic = newInternalClass(QV4::RegExpObject::staticVTable(), objectPrototype()); ic = ic->addMember(id_lastIndex()->propertyKey(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == RegExpObject::Index_LastIndex); - ic = ic->addMember((str = newIdentifier(QStringLiteral("source")))->propertyKey(), Attr_ReadOnly, &index); - Q_ASSERT(index == RegExpObject::Index_Source); - ic = ic->addMember((str = newIdentifier(QStringLiteral("global")))->propertyKey(), Attr_ReadOnly, &index); - Q_ASSERT(index == RegExpObject::Index_Global); - ic = ic->addMember((str = newIdentifier(QStringLiteral("ignoreCase")))->propertyKey(), Attr_ReadOnly, &index); - Q_ASSERT(index == RegExpObject::Index_IgnoreCase); - ic = ic->addMember((str = newIdentifier(QStringLiteral("multiline")))->propertyKey(), Attr_ReadOnly, &index); - Q_ASSERT(index == RegExpObject::Index_Multiline); - ic = ic->addMember((str = newIdentifier(QStringLiteral("unicode")))->propertyKey(), Attr_ReadOnly, &index); - Q_ASSERT(index == RegExpObject::Index_Unicode); jsObjects[RegExpProto] = memoryManager->allocObject<RegExpPrototype>(ic->d()); classes[Class_RegExpObject] = ic->changePrototype(regExpPrototype()->d()); @@ -786,13 +776,8 @@ Heap::DateObject *ExecutionEngine::newDateObjectFromTime(const QTime &t) Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int flags) { - bool global = (flags & QV4::CompiledData::RegExp::RegExp_Global); - bool ignoreCase = (flags & QV4::CompiledData::RegExp::RegExp_IgnoreCase); - bool multiline = (flags & QV4::CompiledData::RegExp::RegExp_Multiline); - bool unicode = (flags & QV4::CompiledData::RegExp::RegExp_Unicode); - Scope scope(this); - Scoped<RegExp> re(scope, RegExp::create(this, pattern, ignoreCase, multiline, global, unicode)); + Scoped<RegExp> re(scope, RegExp::create(this, pattern, static_cast<CompiledData::RegExp::Flags>(flags))); return newRegExpObject(re); } diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index 6963400a08..fe44720b8a 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -76,9 +76,25 @@ uint RegExp::match(const QString &string, int start, uint *matchOffsets) return JSC::Yarr::interpret(byteCode(), s.characters16(), string.length(), start, matchOffsets); } -Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline, bool global, bool unicode) +QString Heap::RegExp::flagsAsString() const { - RegExpCacheKey key(pattern, ignoreCase, multiline, global); + QString result; + if (flags & CompiledData::RegExp::RegExp_Global) + result += QLatin1Char('g'); + if (flags & CompiledData::RegExp::RegExp_IgnoreCase) + result += QLatin1Char('i'); + if (flags & CompiledData::RegExp::RegExp_Multiline) + result += QLatin1Char('m'); + if (flags & CompiledData::RegExp::RegExp_Unicode) + result += QLatin1Char('u'); + if (flags & CompiledData::RegExp::RegExp_Sticky) + result += QLatin1Char('y'); + return result; +} + +Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, uint flags) +{ + RegExpCacheKey key(pattern, flags); RegExpCache *cache = engine->regExpCache; if (!cache) @@ -89,7 +105,7 @@ Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bo return result->d(); Scope scope(engine); - Scoped<RegExp> result(scope, engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline, global, unicode)); + Scoped<RegExp> result(scope, engine->memoryManager->alloc<RegExp>(engine, pattern, flags)); result->d()->cache = cache; cachedValue.set(engine, result); @@ -97,29 +113,28 @@ Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bo return result->d(); } -void Heap::RegExp::init(ExecutionEngine *engine, const QString &pattern, bool ignoreCase, bool multiline, bool global, bool unicode) +void Heap::RegExp::init(ExecutionEngine *engine, const QString &pattern, uint flags) { Base::init(); this->pattern = new QString(pattern); - this->ignoreCase = ignoreCase; - this->multiLine = multiline; - this->unicode = unicode; - this->global = global; + this->flags = flags; valid = false; JSC::Yarr::ErrorCode error = JSC::Yarr::ErrorCode::NoError; - JSC::RegExpFlags flags = JSC::NoFlags; - if (ignoreCase) - flags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagIgnoreCase); - if (multiline) - flags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagMultiline); - if (global) - flags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagGlobal); - if (unicode) - flags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagUnicode); - - JSC::Yarr::YarrPattern yarrPattern(WTF::String(pattern), flags, error); + JSC::RegExpFlags jscFlags = JSC::NoFlags; + if (flags & CompiledData::RegExp::RegExp_Global) + jscFlags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagGlobal); + if (flags & CompiledData::RegExp::RegExp_IgnoreCase) + jscFlags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagIgnoreCase); + if (flags & CompiledData::RegExp::RegExp_Multiline) + jscFlags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagMultiline); + if (flags & CompiledData::RegExp::RegExp_Unicode) + jscFlags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagUnicode); + if (flags & CompiledData::RegExp::RegExp_Sticky) + jscFlags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagSticky); + + JSC::Yarr::YarrPattern yarrPattern(WTF::String(pattern), jscFlags, error); if (error != JSC::Yarr::ErrorCode::NoError) return; subPatternCount = yarrPattern.m_numSubpatterns; diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h index 9090aaa7d5..1e35d141ca 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -76,7 +76,7 @@ struct RegExpCacheKey; namespace Heap { struct RegExp : Base { - void init(ExecutionEngine *engine, const QString& pattern, bool ignoreCase, bool multiline, bool global, bool unicode); + void init(ExecutionEngine *engine, const QString& pattern, uint flags); void destroy(); QString *pattern; @@ -93,12 +93,10 @@ struct RegExp : Base { } RegExpCache *cache; int subPatternCount; - bool ignoreCase; - bool multiLine; - bool global; - bool unicode; + uint flags; bool valid; + QString flagsAsString() const; int captureCount() const { return subPatternCount + 1; } }; Q_STATIC_ASSERT(std::is_trivial< RegExp >::value); @@ -119,11 +117,13 @@ struct RegExp : public Managed #endif RegExpCache *cache() const { return d()->cache; } int subPatternCount() const { return d()->subPatternCount; } - bool ignoreCase() const { return d()->ignoreCase; } - bool multiLine() const { return d()->multiLine; } - bool global() const { return d()->global; } + bool ignoreCase() const { return d()->flags & CompiledData::RegExp::RegExp_IgnoreCase; } + bool multiLine() const { return d()->flags & CompiledData::RegExp::RegExp_Multiline; } + bool global() const { return d()->flags & CompiledData::RegExp::RegExp_Global; } + bool unicode() const { return d()->flags & CompiledData::RegExp::RegExp_Unicode; } + bool sticky() const { return d()->flags & CompiledData::RegExp::RegExp_Sticky; } - static Heap::RegExp *create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false, bool global = false, bool unicode = false); + static Heap::RegExp *create(ExecutionEngine* engine, const QString& pattern, uint flags = CompiledData::RegExp::RegExp_NoFlags); bool isValid() const { return d()->valid; } @@ -136,30 +136,23 @@ struct RegExp : public Managed struct RegExpCacheKey { - RegExpCacheKey(const QString &pattern, bool ignoreCase, bool multiLine, bool global) - : pattern(pattern) - , ignoreCase(ignoreCase) - , multiLine(multiLine) - , global(global) + RegExpCacheKey(const QString &pattern, uint flags) + : pattern(pattern), flags(flags) { } explicit inline RegExpCacheKey(const RegExp::Data *re); bool operator==(const RegExpCacheKey &other) const - { return pattern == other.pattern && ignoreCase == other.ignoreCase && multiLine == other.multiLine && global == other.global; } + { return pattern == other.pattern && flags == other.flags;; } bool operator!=(const RegExpCacheKey &other) const { return !operator==(other); } QString pattern; - uint ignoreCase : 1; - uint multiLine : 1; - uint global : 1; + uint flags; }; inline RegExpCacheKey::RegExpCacheKey(const RegExp::Data *re) : pattern(*re->pattern) - , ignoreCase(re->ignoreCase) - , multiLine(re->multiLine) - , global(re->global) + , flags(re->flags) {} inline uint qHash(const RegExpCacheKey& key, uint seed = 0) Q_DECL_NOTHROW 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) { diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index 74ea8aea4e..71936e2450 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -76,7 +76,7 @@ namespace Heap { Member(class, Pointer, RegExp *, value) DECLARE_HEAP_OBJECT(RegExpObject, Object) { - DECLARE_MARKOBJECTS(RegExpObject); + DECLARE_MARKOBJECTS(RegExpObject) void init(); void init(QV4::RegExp *value); @@ -109,16 +109,12 @@ struct RegExpObject: Object { RegExp_Global = 0x01, RegExp_IgnoreCase = 0x02, RegExp_Multiline = 0x04, - RegExp_Unicode = 0x08 + RegExp_Unicode = 0x08, + RegExp_Sticky = 0x10 }; enum { Index_LastIndex = 0, - Index_Source = 1, - Index_Global = 2, - Index_IgnoreCase = 3, - Index_Multiline = 4, - Index_Unicode = 5, Index_ArrayIndex = Heap::ArrayObject::LengthPropertyIndex + 1, Index_ArrayInput = Index_ArrayIndex + 1 }; @@ -126,7 +122,7 @@ struct RegExpObject: Object { enum { NInlineProperties = 5 }; Heap::RegExp *value() const { return d()->value; } - bool global() const { return d()->value->global; } + bool global() const { return d()->value->flags & CompiledData::RegExp::RegExp_Global; } void initProperties(); @@ -165,13 +161,21 @@ struct RegExpPrototype: RegExpObject void init(ExecutionEngine *engine, Object *ctor); static ReturnedValue method_exec(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_get_flags(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_get_global(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_get_ignoreCase(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_match(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_get_multiline(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_get_source(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_get_sticky(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_test(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_compile(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); - - static ReturnedValue method_match(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_get_unicode(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + // Web extension + static ReturnedValue method_compile(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + // properties on the constructor, web extensions template <uint index> static ReturnedValue method_get_lastMatch_n(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_get_lastParen(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp index e93dda942a..b98bb8bac5 100644 --- a/src/qml/parser/qqmljslexer.cpp +++ b/src/qml/parser/qqmljslexer.cpp @@ -59,6 +59,7 @@ static inline int regExpFlagFromChar(const QChar &ch) case 'i': return Lexer::RegExp_IgnoreCase; case 'm': return Lexer::RegExp_Multiline; case 'u': return Lexer::RegExp_Unicode; + case 'y': return Lexer::RegExp_Sticky; } return 0; } diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h index 64db62625a..644c5c09aa 100644 --- a/src/qml/parser/qqmljslexer_p.h +++ b/src/qml/parser/qqmljslexer_p.h @@ -114,7 +114,8 @@ public: RegExp_Global = 0x01, RegExp_IgnoreCase = 0x02, RegExp_Multiline = 0x04, - RegExp_Unicode = 0x08 + RegExp_Unicode = 0x08, + RegExp_Sticky = 0x10 }; enum ParseModeFlags { |
