]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/RegExpObject.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / RegExpObject.cpp
CommitLineData
9dae56ea
A
1/*
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
6fe7ccc8 3 * Copyright (C) 2003, 2007, 2008, 2012 Apple Inc. All Rights Reserved.
9dae56ea
A
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
93a37866
A
24#include "ButterflyInlines.h"
25#include "CopiedSpaceInlines.h"
ba379fdc 26#include "Error.h"
14957cd0 27#include "ExceptionHelpers.h"
9dae56ea
A
28#include "JSArray.h"
29#include "JSGlobalObject.h"
30#include "JSString.h"
4e4e5a6f 31#include "Lookup.h"
81345200 32#include "JSCInlines.h"
9dae56ea 33#include "RegExpConstructor.h"
6fe7ccc8 34#include "RegExpMatchesArray.h"
9dae56ea 35#include "RegExpPrototype.h"
93a37866 36#include <wtf/text/StringBuilder.h>
14957cd0 37
9dae56ea
A
38namespace JSC {
39
81345200 40STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(RegExpObject);
9dae56ea 41
ed1e77d3 42const ClassInfo RegExpObject::s_info = { "RegExp", &Base::s_info, nullptr, CREATE_METHOD_TABLE(RegExpObject) };
9dae56ea 43
81345200
A
44RegExpObject::RegExpObject(VM& vm, Structure* structure, RegExp* regExp)
45 : JSNonFinalObject(vm, structure)
46 , m_regExp(vm, this, regExp)
6fe7ccc8 47 , m_lastIndexIsWritable(true)
9dae56ea 48{
6fe7ccc8 49 m_lastIndex.setWithoutWriteBarrier(jsNumber(0));
9dae56ea
A
50}
51
81345200 52void RegExpObject::finishCreation(VM& vm)
9dae56ea 53{
81345200
A
54 Base::finishCreation(vm);
55 ASSERT(inherits(info()));
9dae56ea
A
56}
57
6fe7ccc8 58void RegExpObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
14957cd0 59{
6fe7ccc8 60 RegExpObject* thisObject = jsCast<RegExpObject*>(cell);
81345200 61 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
6fe7ccc8 62 Base::visitChildren(thisObject, visitor);
93a37866
A
63 visitor.append(&thisObject->m_regExp);
64 visitor.append(&thisObject->m_lastIndex);
6fe7ccc8
A
65}
66
81345200 67bool RegExpObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
9dae56ea 68{
6fe7ccc8
A
69 if (propertyName == exec->propertyNames().lastIndex) {
70 RegExpObject* regExp = asRegExpObject(object);
81345200
A
71 unsigned attributes = regExp->m_lastIndexIsWritable ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly;
72 slot.setValue(regExp, attributes, regExp->getLastIndex());
6fe7ccc8
A
73 return true;
74 }
ed1e77d3 75 return Base::getOwnPropertySlot(object, exec, propertyName, slot);
6fe7ccc8
A
76}
77
93a37866 78bool RegExpObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
6fe7ccc8
A
79{
80 if (propertyName == exec->propertyNames().lastIndex)
81 return false;
82 return Base::deleteProperty(cell, exec, propertyName);
9dae56ea
A
83}
84
93a37866 85void RegExpObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
f9bf01c6 86{
ed1e77d3 87 if (mode.includeDontEnumProperties())
6fe7ccc8 88 propertyNames.add(exec->propertyNames().lastIndex);
93a37866 89 Base::getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
6fe7ccc8
A
90}
91
92void RegExpObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
93{
ed1e77d3 94 if (mode.includeDontEnumProperties())
6fe7ccc8
A
95 propertyNames.add(exec->propertyNames().lastIndex);
96 Base::getPropertyNames(object, exec, propertyNames, mode);
97}
98
ed1e77d3
A
99void RegExpObject::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
100{
101 if (mode.includeDontEnumProperties())
102 propertyNames.add(exec->propertyNames().lastIndex);
103 Base::getGenericPropertyNames(object, exec, propertyNames, mode);
104}
105
6fe7ccc8
A
106static bool reject(ExecState* exec, bool throwException, const char* message)
107{
108 if (throwException)
93a37866 109 throwTypeError(exec, ASCIILiteral(message));
6fe7ccc8
A
110 return false;
111}
112
81345200 113bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
6fe7ccc8
A
114{
115 if (propertyName == exec->propertyNames().lastIndex) {
116 RegExpObject* regExp = asRegExpObject(object);
117 if (descriptor.configurablePresent() && descriptor.configurable())
118 return reject(exec, shouldThrow, "Attempting to change configurable attribute of unconfigurable property.");
119 if (descriptor.enumerablePresent() && descriptor.enumerable())
120 return reject(exec, shouldThrow, "Attempting to change enumerable attribute of unconfigurable property.");
121 if (descriptor.isAccessorDescriptor())
122 return reject(exec, shouldThrow, "Attempting to change access mechanism for an unconfigurable property.");
123 if (!regExp->m_lastIndexIsWritable) {
124 if (descriptor.writablePresent() && descriptor.writable())
125 return reject(exec, shouldThrow, "Attempting to change writable attribute of unconfigurable property.");
126 if (!sameValue(exec, regExp->getLastIndex(), descriptor.value()))
127 return reject(exec, shouldThrow, "Attempting to change value of a readonly property.");
128 return true;
129 }
130 if (descriptor.writablePresent() && !descriptor.writable())
131 regExp->m_lastIndexIsWritable = false;
132 if (descriptor.value())
133 regExp->setLastIndex(exec, descriptor.value(), false);
134 return true;
135 }
136
137 return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
f9bf01c6
A
138}
139
ed1e77d3 140static void regExpObjectSetLastIndexStrict(ExecState* exec, JSObject* slotBase, EncodedJSValue, EncodedJSValue value)
9dae56ea 141{
ed1e77d3 142 asRegExpObject(slotBase)->setLastIndex(exec, JSValue::decode(value), true);
93a37866
A
143}
144
ed1e77d3 145static void regExpObjectSetLastIndexNonStrict(ExecState* exec, JSObject* slotBase, EncodedJSValue, EncodedJSValue value)
93a37866 146{
ed1e77d3 147 asRegExpObject(slotBase)->setLastIndex(exec, JSValue::decode(value), false);
9dae56ea
A
148}
149
93a37866 150void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
9dae56ea 151{
6fe7ccc8
A
152 if (propertyName == exec->propertyNames().lastIndex) {
153 asRegExpObject(cell)->setLastIndex(exec, value, slot.isStrictMode());
ed1e77d3
A
154 slot.setCustomProperty(asRegExpObject(cell), slot.isStrictMode()
155 ? regExpObjectSetLastIndexStrict
156 : regExpObjectSetLastIndexNonStrict);
6fe7ccc8
A
157 return;
158 }
81345200 159 Base::put(cell, exec, propertyName, value, slot);
9dae56ea
A
160}
161
6fe7ccc8 162JSValue RegExpObject::exec(ExecState* exec, JSString* string)
9dae56ea 163{
6fe7ccc8 164 if (MatchResult result = match(exec, string))
ed1e77d3 165 return createRegExpMatchesArray(exec, string, regExp(), result);
9dae56ea
A
166 return jsNull();
167}
168
9dae56ea 169// Shared implementation used by test and exec.
6fe7ccc8 170MatchResult RegExpObject::match(ExecState* exec, JSString* string)
9dae56ea 171{
6fe7ccc8 172 RegExp* regExp = this->regExp();
9dae56ea 173 RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
93a37866
A
174 String input = string->value(exec);
175 VM& vm = exec->vm();
6fe7ccc8 176 if (!regExp->global())
93a37866 177 return regExpConstructor->performMatch(vm, regExp, string, input, 0);
9dae56ea 178
14957cd0
A
179 JSValue jsLastIndex = getLastIndex();
180 unsigned lastIndex;
181 if (LIKELY(jsLastIndex.isUInt32())) {
182 lastIndex = jsLastIndex.asUInt32();
183 if (lastIndex > input.length()) {
6fe7ccc8
A
184 setLastIndex(exec, 0);
185 return MatchResult::failed();
14957cd0
A
186 }
187 } else {
188 double doubleLastIndex = jsLastIndex.toInteger(exec);
189 if (doubleLastIndex < 0 || doubleLastIndex > input.length()) {
6fe7ccc8
A
190 setLastIndex(exec, 0);
191 return MatchResult::failed();
14957cd0
A
192 }
193 lastIndex = static_cast<unsigned>(doubleLastIndex);
9dae56ea
A
194 }
195
93a37866 196 MatchResult result = regExpConstructor->performMatch(vm, regExp, string, input, lastIndex);
6fe7ccc8
A
197 setLastIndex(exec, result.end);
198 return result;
9dae56ea
A
199}
200
201} // namespace JSC