2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "RegExpObject.h"
25 #include "ExceptionHelpers.h"
27 #include "JSGlobalObject.h"
31 #include "RegExpConstructor.h"
32 #include "RegExpPrototype.h"
33 #include "UStringBuilder.h"
34 #include "UStringConcatenate.h"
35 #include <wtf/PassOwnPtr.h>
39 static JSValue regExpObjectGlobal(ExecState*, JSValue, const Identifier&);
40 static JSValue regExpObjectIgnoreCase(ExecState*, JSValue, const Identifier&);
41 static JSValue regExpObjectMultiline(ExecState*, JSValue, const Identifier&);
42 static JSValue regExpObjectSource(ExecState*, JSValue, const Identifier&);
43 static JSValue regExpObjectLastIndex(ExecState*, JSValue, const Identifier&);
44 static void setRegExpObjectLastIndex(ExecState*, JSObject*, JSValue);
48 #include "RegExpObject.lut.h"
52 ASSERT_CLASS_FITS_IN_CELL(RegExpObject);
54 const ClassInfo RegExpObject::s_info = { "RegExp", &JSNonFinalObject::s_info, 0, ExecState::regExpTable, CREATE_METHOD_TABLE(RegExpObject) };
56 /* Source for RegExpObject.lut.h
58 global regExpObjectGlobal DontDelete|ReadOnly|DontEnum
59 ignoreCase regExpObjectIgnoreCase DontDelete|ReadOnly|DontEnum
60 multiline regExpObjectMultiline DontDelete|ReadOnly|DontEnum
61 source regExpObjectSource DontDelete|ReadOnly|DontEnum
62 lastIndex regExpObjectLastIndex DontDelete|DontEnum
66 RegExpObject::RegExpObject(JSGlobalObject* globalObject, Structure* structure, RegExp* regExp)
67 : JSNonFinalObject(globalObject->globalData(), structure)
68 , d(adoptPtr(new RegExpObjectData(globalObject->globalData(), this, regExp)))
72 void RegExpObject::finishCreation(JSGlobalObject* globalObject)
74 Base::finishCreation(globalObject->globalData());
75 ASSERT(inherits(&s_info));
78 RegExpObject::~RegExpObject()
82 void RegExpObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
84 RegExpObject* thisObject = jsCast<RegExpObject*>(cell);
85 ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
86 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
87 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
88 Base::visitChildren(thisObject, visitor);
89 if (thisObject->d->regExp)
90 visitor.append(&thisObject->d->regExp);
91 if (UNLIKELY(!thisObject->d->lastIndex.get().isInt32()))
92 visitor.append(&thisObject->d->lastIndex);
95 bool RegExpObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
97 return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), jsCast<RegExpObject*>(cell), propertyName, slot);
100 bool RegExpObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
102 return getStaticValueDescriptor<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), jsCast<RegExpObject*>(object), propertyName, descriptor);
105 JSValue regExpObjectGlobal(ExecState*, JSValue slotBase, const Identifier&)
107 return jsBoolean(asRegExpObject(slotBase)->regExp()->global());
110 JSValue regExpObjectIgnoreCase(ExecState*, JSValue slotBase, const Identifier&)
112 return jsBoolean(asRegExpObject(slotBase)->regExp()->ignoreCase());
115 JSValue regExpObjectMultiline(ExecState*, JSValue slotBase, const Identifier&)
117 return jsBoolean(asRegExpObject(slotBase)->regExp()->multiline());
120 JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, const Identifier&)
122 UString pattern = asRegExpObject(slotBase)->regExp()->pattern();
123 unsigned length = pattern.length();
124 const UChar* characters = pattern.characters();
125 bool previousCharacterWasBackslash = false;
126 bool inBrackets = false;
127 bool shouldEscape = false;
129 // early return for strings that don't contain a forwards slash and LineTerminator
130 for (unsigned i = 0; i < length; ++i) {
131 UChar ch = characters[i];
132 if (!previousCharacterWasBackslash) {
146 if (Lexer<UChar>::isLineTerminator(ch)) {
151 if (previousCharacterWasBackslash)
152 previousCharacterWasBackslash = false;
154 previousCharacterWasBackslash = ch == '\\';
158 return jsString(exec, pattern);
160 previousCharacterWasBackslash = false;
162 UStringBuilder result;
163 for (unsigned i = 0; i < length; ++i) {
164 UChar ch = characters[i];
165 if (!previousCharacterWasBackslash) {
177 // escape LineTerminator
178 if (Lexer<UChar>::isLineTerminator(ch)) {
179 if (!previousCharacterWasBackslash)
186 else if (ch == 0x2028)
187 result.append("u2028");
189 result.append("u2029");
193 if (previousCharacterWasBackslash)
194 previousCharacterWasBackslash = false;
196 previousCharacterWasBackslash = ch == '\\';
199 return jsString(exec, result.toUString());
202 JSValue regExpObjectLastIndex(ExecState*, JSValue slotBase, const Identifier&)
204 return asRegExpObject(slotBase)->getLastIndex();
207 void RegExpObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
209 lookupPut<RegExpObject, JSObject>(exec, propertyName, value, ExecState::regExpTable(exec), jsCast<RegExpObject*>(cell), slot);
212 void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value)
214 asRegExpObject(baseObject)->setLastIndex(exec->globalData(), value);
217 JSValue RegExpObject::test(ExecState* exec)
219 return jsBoolean(match(exec));
222 JSValue RegExpObject::exec(ExecState* exec)
225 return exec->lexicalGlobalObject()->regExpConstructor()->arrayOfMatches(exec);
229 // Shared implementation used by test and exec.
230 bool RegExpObject::match(ExecState* exec)
232 RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
233 UString input = exec->argument(0).toString(exec);
234 JSGlobalData* globalData = &exec->globalData();
235 if (!regExp()->global()) {
238 regExpConstructor->performMatch(*globalData, d->regExp.get(), input, 0, position, length);
239 return position >= 0;
242 JSValue jsLastIndex = getLastIndex();
244 if (LIKELY(jsLastIndex.isUInt32())) {
245 lastIndex = jsLastIndex.asUInt32();
246 if (lastIndex > input.length()) {
251 double doubleLastIndex = jsLastIndex.toInteger(exec);
252 if (doubleLastIndex < 0 || doubleLastIndex > input.length()) {
256 lastIndex = static_cast<unsigned>(doubleLastIndex);
261 regExpConstructor->performMatch(*globalData, d->regExp.get(), input, lastIndex, position, length);
267 setLastIndex(position + length);