1 /* 2 * Copyright (C) 1999-2000 Harri Porten (porten (at) 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 35 namespace JSC { 36 37 static JSValue regExpObjectGlobal(ExecState*, JSValue, const Identifier&); 38 static JSValue regExpObjectIgnoreCase(ExecState*, JSValue, const Identifier&); 39 static JSValue regExpObjectMultiline(ExecState*, JSValue, const Identifier&); 40 static JSValue regExpObjectSource(ExecState*, JSValue, const Identifier&); 41 static JSValue regExpObjectLastIndex(ExecState*, JSValue, const Identifier&); 42 static void setRegExpObjectLastIndex(ExecState*, JSObject*, JSValue); 43 44 } // namespace JSC 45 46 #include "RegExpObject.lut.h" 47 48 namespace JSC { 49 50 ASSERT_CLASS_FITS_IN_CELL(RegExpObject); 51 52 const 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 64 RegExpObject::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 71 RegExpObject::~RegExpObject() 72 { 73 } 74 75 void RegExpObject::markChildren(MarkStack& markStack) 76 { 77 Base::markChildren(markStack); 78 if (UNLIKELY(!d->lastIndex.get().isInt32())) 79 markStack.append(&d->lastIndex); 80 } 81 82 bool RegExpObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) 83 { 84 return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, slot); 85 } 86 87 bool RegExpObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) 88 { 89 return getStaticValueDescriptor<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, descriptor); 90 } 91 92 JSValue regExpObjectGlobal(ExecState*, JSValue slotBase, const Identifier&) 93 { 94 return jsBoolean(asRegExpObject(slotBase)->regExp()->global()); 95 } 96 97 JSValue regExpObjectIgnoreCase(ExecState*, JSValue slotBase, const Identifier&) 98 { 99 return jsBoolean(asRegExpObject(slotBase)->regExp()->ignoreCase()); 100 } 101 102 JSValue regExpObjectMultiline(ExecState*, JSValue slotBase, const Identifier&) 103 { 104 return jsBoolean(asRegExpObject(slotBase)->regExp()->multiline()); 105 } 106 107 JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, const Identifier&) 108 { 109 return jsString(exec, asRegExpObject(slotBase)->regExp()->pattern()); 110 } 111 112 JSValue regExpObjectLastIndex(ExecState*, JSValue slotBase, const Identifier&) 113 { 114 return asRegExpObject(slotBase)->getLastIndex(); 115 } 116 117 void 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 122 void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value) 123 { 124 asRegExpObject(baseObject)->setLastIndex(exec->globalData(), value); 125 } 126 127 JSValue RegExpObject::test(ExecState* exec) 128 { 129 return jsBoolean(match(exec)); 130 } 131 132 JSValue 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. 140 bool 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