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