1/* 2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) 3 * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved. 4 * 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. 9 * 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. 14 * 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 18 * 19 */ 20 21#include "config.h" 22#include "RegExpObject.h" 23 24#include "Error.h" 25#include "ExceptionHelpers.h" 26#include "JSArray.h" 27#include "JSGlobalObject.h" 28#include "JSString.h" 29#include "Lookup.h" 30#include "RegExpConstructor.h" 31#include "RegExpPrototype.h" 32#include "UStringConcatenate.h" 33#include <wtf/PassOwnPtr.h> 34 35namespace JSC { 36 37static JSValue regExpObjectGlobal(ExecState*, JSValue, const Identifier&); 38static JSValue regExpObjectIgnoreCase(ExecState*, JSValue, const Identifier&); 39static JSValue regExpObjectMultiline(ExecState*, JSValue, const Identifier&); 40static JSValue regExpObjectSource(ExecState*, JSValue, const Identifier&); 41static JSValue regExpObjectLastIndex(ExecState*, JSValue, const Identifier&); 42static void setRegExpObjectLastIndex(ExecState*, JSObject*, JSValue); 43 44} // namespace JSC 45 46#include "RegExpObject.lut.h" 47 48namespace JSC { 49 50ASSERT_CLASS_FITS_IN_CELL(RegExpObject); 51 52const ClassInfo RegExpObject::s_info = { "RegExp", &JSObjectWithGlobalObject::s_info, 0, ExecState::regExpTable }; 53 54/* Source for RegExpObject.lut.h 55@begin regExpTable 56 global regExpObjectGlobal DontDelete|ReadOnly|DontEnum 57 ignoreCase regExpObjectIgnoreCase DontDelete|ReadOnly|DontEnum 58 multiline regExpObjectMultiline DontDelete|ReadOnly|DontEnum 59 source regExpObjectSource DontDelete|ReadOnly|DontEnum 60 lastIndex regExpObjectLastIndex DontDelete|DontEnum 61@end 62*/ 63 64RegExpObject::RegExpObject(JSGlobalObject* globalObject, Structure* structure, NonNullPassRefPtr<RegExp> regExp) 65 : JSObjectWithGlobalObject(globalObject, structure) 66 , d(adoptPtr(new RegExpObjectData(regExp))) 67{ 68 ASSERT(inherits(&s_info)); 69} 70 71RegExpObject::~RegExpObject() 72{ 73} 74 75void RegExpObject::markChildren(MarkStack& markStack) 76{ 77 Base::markChildren(markStack); 78 if (UNLIKELY(!d->lastIndex.get().isInt32())) 79 markStack.append(&d->lastIndex); 80} 81 82bool RegExpObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) 83{ 84 return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, slot); 85} 86 87bool RegExpObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) 88{ 89 return getStaticValueDescriptor<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, descriptor); 90} 91 92JSValue regExpObjectGlobal(ExecState*, JSValue slotBase, const Identifier&) 93{ 94 return jsBoolean(asRegExpObject(slotBase)->regExp()->global()); 95} 96 97JSValue regExpObjectIgnoreCase(ExecState*, JSValue slotBase, const Identifier&) 98{ 99 return jsBoolean(asRegExpObject(slotBase)->regExp()->ignoreCase()); 100} 101 102JSValue regExpObjectMultiline(ExecState*, JSValue slotBase, const Identifier&) 103{ 104 return jsBoolean(asRegExpObject(slotBase)->regExp()->multiline()); 105} 106 107JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, const Identifier&) 108{ 109 return jsString(exec, asRegExpObject(slotBase)->regExp()->pattern()); 110} 111 112JSValue regExpObjectLastIndex(ExecState*, JSValue slotBase, const Identifier&) 113{ 114 return asRegExpObject(slotBase)->getLastIndex(); 115} 116 117void RegExpObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) 118{ 119 lookupPut<RegExpObject, JSObject>(exec, propertyName, value, ExecState::regExpTable(exec), this, slot); 120} 121 122void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value) 123{ 124 asRegExpObject(baseObject)->setLastIndex(exec->globalData(), value); 125} 126 127JSValue RegExpObject::test(ExecState* exec) 128{ 129 return jsBoolean(match(exec)); 130} 131 132JSValue RegExpObject::exec(ExecState* exec) 133{ 134 if (match(exec)) 135 return exec->lexicalGlobalObject()->regExpConstructor()->arrayOfMatches(exec); 136 return jsNull(); 137} 138 139// Shared implementation used by test and exec. 140bool RegExpObject::match(ExecState* exec) 141{ 142 RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); 143 UString input = exec->argument(0).toString(exec); 144 145 if (!regExp()->global()) { 146 int position; 147 int length; 148 regExpConstructor->performMatch(d->regExp.get(), input, 0, position, length); 149 return position >= 0; 150 } 151 152 JSValue jsLastIndex = getLastIndex(); 153 unsigned lastIndex; 154 if (LIKELY(jsLastIndex.isUInt32())) { 155 lastIndex = jsLastIndex.asUInt32(); 156 if (lastIndex > input.length()) { 157 setLastIndex(0); 158 return false; 159 } 160 } else { 161 double doubleLastIndex = jsLastIndex.toInteger(exec); 162 if (doubleLastIndex < 0 || doubleLastIndex > input.length()) { 163 setLastIndex(0); 164 return false; 165 } 166 lastIndex = static_cast<unsigned>(doubleLastIndex); 167 } 168 169 int position; 170 int length = 0; 171 regExpConstructor->performMatch(d->regExp.get(), input, lastIndex, position, length); 172 if (position < 0) { 173 setLastIndex(0); 174 return false; 175 } 176 177 setLastIndex(position + length); 178 return true; 179} 180 181} // namespace JSC 182