summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/RegExpObject.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
commit40736c5763bf61337c8c14e16d8587db021a87d4 (patch)
treeb17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/JavaScriptCore/runtime/RegExpObject.cpp
downloadqtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/JavaScriptCore/runtime/RegExpObject.cpp')
-rw-r--r--Source/JavaScriptCore/runtime/RegExpObject.cpp272
1 files changed, 272 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp
new file mode 100644
index 000000000..4553f7ad0
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "RegExpObject.h"
+
+#include "Error.h"
+#include "ExceptionHelpers.h"
+#include "JSArray.h"
+#include "JSGlobalObject.h"
+#include "JSString.h"
+#include "Lexer.h"
+#include "Lookup.h"
+#include "RegExpConstructor.h"
+#include "RegExpPrototype.h"
+#include "UStringBuilder.h"
+#include "UStringConcatenate.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace JSC {
+
+static JSValue regExpObjectGlobal(ExecState*, JSValue, const Identifier&);
+static JSValue regExpObjectIgnoreCase(ExecState*, JSValue, const Identifier&);
+static JSValue regExpObjectMultiline(ExecState*, JSValue, const Identifier&);
+static JSValue regExpObjectSource(ExecState*, JSValue, const Identifier&);
+static JSValue regExpObjectLastIndex(ExecState*, JSValue, const Identifier&);
+static void setRegExpObjectLastIndex(ExecState*, JSObject*, JSValue);
+
+} // namespace JSC
+
+#include "RegExpObject.lut.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(RegExpObject);
+
+const ClassInfo RegExpObject::s_info = { "RegExp", &JSNonFinalObject::s_info, 0, ExecState::regExpTable, CREATE_METHOD_TABLE(RegExpObject) };
+
+/* Source for RegExpObject.lut.h
+@begin regExpTable
+ global regExpObjectGlobal DontDelete|ReadOnly|DontEnum
+ ignoreCase regExpObjectIgnoreCase DontDelete|ReadOnly|DontEnum
+ multiline regExpObjectMultiline DontDelete|ReadOnly|DontEnum
+ source regExpObjectSource DontDelete|ReadOnly|DontEnum
+ lastIndex regExpObjectLastIndex DontDelete|DontEnum
+@end
+*/
+
+RegExpObject::RegExpObject(JSGlobalObject* globalObject, Structure* structure, RegExp* regExp)
+ : JSNonFinalObject(globalObject->globalData(), structure)
+ , d(adoptPtr(new RegExpObjectData(globalObject->globalData(), this, regExp)))
+{
+}
+
+void RegExpObject::finishCreation(JSGlobalObject* globalObject)
+{
+ Base::finishCreation(globalObject->globalData());
+ ASSERT(inherits(&s_info));
+}
+
+void RegExpObject::destroy(JSCell* cell)
+{
+ jsCast<RegExpObject*>(cell)->RegExpObject::~RegExpObject();
+}
+
+void RegExpObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ RegExpObject* thisObject = jsCast<RegExpObject*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ Base::visitChildren(thisObject, visitor);
+ if (thisObject->d->regExp)
+ visitor.append(&thisObject->d->regExp);
+ if (UNLIKELY(!thisObject->d->lastIndex.get().isInt32()))
+ visitor.append(&thisObject->d->lastIndex);
+}
+
+bool RegExpObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), jsCast<RegExpObject*>(cell), propertyName, slot);
+}
+
+bool RegExpObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticValueDescriptor<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), jsCast<RegExpObject*>(object), propertyName, descriptor);
+}
+
+JSValue regExpObjectGlobal(ExecState*, JSValue slotBase, const Identifier&)
+{
+ return jsBoolean(asRegExpObject(slotBase)->regExp()->global());
+}
+
+JSValue regExpObjectIgnoreCase(ExecState*, JSValue slotBase, const Identifier&)
+{
+ return jsBoolean(asRegExpObject(slotBase)->regExp()->ignoreCase());
+}
+
+JSValue regExpObjectMultiline(ExecState*, JSValue slotBase, const Identifier&)
+{
+ return jsBoolean(asRegExpObject(slotBase)->regExp()->multiline());
+}
+
+JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ UString pattern = asRegExpObject(slotBase)->regExp()->pattern();
+ unsigned length = pattern.length();
+ const UChar* characters = pattern.characters();
+ bool previousCharacterWasBackslash = false;
+ bool inBrackets = false;
+ bool shouldEscape = false;
+
+ // early return for strings that don't contain a forwards slash and LineTerminator
+ for (unsigned i = 0; i < length; ++i) {
+ UChar ch = characters[i];
+ if (!previousCharacterWasBackslash) {
+ if (inBrackets) {
+ if (ch == ']')
+ inBrackets = false;
+ } else {
+ if (ch == '/') {
+ shouldEscape = true;
+ break;
+ }
+ if (ch == '[')
+ inBrackets = true;
+ }
+ }
+
+ if (Lexer<UChar>::isLineTerminator(ch)) {
+ shouldEscape = true;
+ break;
+ }
+
+ if (previousCharacterWasBackslash)
+ previousCharacterWasBackslash = false;
+ else
+ previousCharacterWasBackslash = ch == '\\';
+ }
+
+ if (!shouldEscape)
+ return jsString(exec, pattern);
+
+ previousCharacterWasBackslash = false;
+ inBrackets = false;
+ UStringBuilder result;
+ for (unsigned i = 0; i < length; ++i) {
+ UChar ch = characters[i];
+ if (!previousCharacterWasBackslash) {
+ if (inBrackets) {
+ if (ch == ']')
+ inBrackets = false;
+ } else {
+ if (ch == '/')
+ result.append('\\');
+ else if (ch == '[')
+ inBrackets = true;
+ }
+ }
+
+ // escape LineTerminator
+ if (Lexer<UChar>::isLineTerminator(ch)) {
+ if (!previousCharacterWasBackslash)
+ result.append('\\');
+
+ if (ch == '\n')
+ result.append('n');
+ else if (ch == '\r')
+ result.append('r');
+ else if (ch == 0x2028)
+ result.append("u2028");
+ else
+ result.append("u2029");
+ } else
+ result.append(ch);
+
+ if (previousCharacterWasBackslash)
+ previousCharacterWasBackslash = false;
+ else
+ previousCharacterWasBackslash = ch == '\\';
+ }
+
+ return jsString(exec, result.toUString());
+}
+
+JSValue regExpObjectLastIndex(ExecState*, JSValue slotBase, const Identifier&)
+{
+ return asRegExpObject(slotBase)->getLastIndex();
+}
+
+void RegExpObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ lookupPut<RegExpObject, JSObject>(exec, propertyName, value, ExecState::regExpTable(exec), jsCast<RegExpObject*>(cell), slot);
+}
+
+void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value)
+{
+ asRegExpObject(baseObject)->setLastIndex(exec->globalData(), value);
+}
+
+JSValue RegExpObject::test(ExecState* exec)
+{
+ return jsBoolean(match(exec));
+}
+
+JSValue RegExpObject::exec(ExecState* exec)
+{
+ if (match(exec))
+ return exec->lexicalGlobalObject()->regExpConstructor()->arrayOfMatches(exec);
+ return jsNull();
+}
+
+// Shared implementation used by test and exec.
+bool RegExpObject::match(ExecState* exec)
+{
+ RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
+ UString input = exec->argument(0).toString(exec);
+ JSGlobalData* globalData = &exec->globalData();
+ if (!regExp()->global()) {
+ int position;
+ int length;
+ regExpConstructor->performMatch(*globalData, d->regExp.get(), input, 0, position, length);
+ return position >= 0;
+ }
+
+ JSValue jsLastIndex = getLastIndex();
+ unsigned lastIndex;
+ if (LIKELY(jsLastIndex.isUInt32())) {
+ lastIndex = jsLastIndex.asUInt32();
+ if (lastIndex > input.length()) {
+ setLastIndex(0);
+ return false;
+ }
+ } else {
+ double doubleLastIndex = jsLastIndex.toInteger(exec);
+ if (doubleLastIndex < 0 || doubleLastIndex > input.length()) {
+ setLastIndex(0);
+ return false;
+ }
+ lastIndex = static_cast<unsigned>(doubleLastIndex);
+ }
+
+ int position;
+ int length = 0;
+ regExpConstructor->performMatch(*globalData, d->regExp.get(), input, lastIndex, position, length);
+ if (position < 0) {
+ setLastIndex(0);
+ return false;
+ }
+
+ setLastIndex(position + length);
+ return true;
+}
+
+} // namespace JSC