]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/RegExpConstructor.cpp
JavaScriptCore-1218.33.tar.gz
[apple/javascriptcore.git] / runtime / RegExpConstructor.cpp
1 /*
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved.
4 * Copyright (C) 2009 Torch Mobile, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 #include "config.h"
23 #include "RegExpConstructor.h"
24
25 #include "Error.h"
26 #include "Operations.h"
27 #include "RegExpMatchesArray.h"
28 #include "RegExpPrototype.h"
29
30 #if PLATFORM(IOS)
31 #include <wtf/PassOwnPtr.h>
32 #endif
33
34 namespace JSC {
35
36 static JSValue regExpConstructorInput(ExecState*, JSValue, PropertyName);
37 static JSValue regExpConstructorMultiline(ExecState*, JSValue, PropertyName);
38 static JSValue regExpConstructorLastMatch(ExecState*, JSValue, PropertyName);
39 static JSValue regExpConstructorLastParen(ExecState*, JSValue, PropertyName);
40 static JSValue regExpConstructorLeftContext(ExecState*, JSValue, PropertyName);
41 static JSValue regExpConstructorRightContext(ExecState*, JSValue, PropertyName);
42 static JSValue regExpConstructorDollar1(ExecState*, JSValue, PropertyName);
43 static JSValue regExpConstructorDollar2(ExecState*, JSValue, PropertyName);
44 static JSValue regExpConstructorDollar3(ExecState*, JSValue, PropertyName);
45 static JSValue regExpConstructorDollar4(ExecState*, JSValue, PropertyName);
46 static JSValue regExpConstructorDollar5(ExecState*, JSValue, PropertyName);
47 static JSValue regExpConstructorDollar6(ExecState*, JSValue, PropertyName);
48 static JSValue regExpConstructorDollar7(ExecState*, JSValue, PropertyName);
49 static JSValue regExpConstructorDollar8(ExecState*, JSValue, PropertyName);
50 static JSValue regExpConstructorDollar9(ExecState*, JSValue, PropertyName);
51
52 static void setRegExpConstructorInput(ExecState*, JSObject*, JSValue);
53 static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValue);
54
55 } // namespace JSC
56
57 #include "RegExpConstructor.lut.h"
58
59 namespace JSC {
60
61 const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::regExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) };
62
63 /* Source for RegExpConstructor.lut.h
64 @begin regExpConstructorTable
65 input regExpConstructorInput None
66 $_ regExpConstructorInput DontEnum
67 multiline regExpConstructorMultiline None
68 $* regExpConstructorMultiline DontEnum
69 lastMatch regExpConstructorLastMatch DontDelete|ReadOnly
70 $& regExpConstructorLastMatch DontDelete|ReadOnly|DontEnum
71 lastParen regExpConstructorLastParen DontDelete|ReadOnly
72 $+ regExpConstructorLastParen DontDelete|ReadOnly|DontEnum
73 leftContext regExpConstructorLeftContext DontDelete|ReadOnly
74 $` regExpConstructorLeftContext DontDelete|ReadOnly|DontEnum
75 rightContext regExpConstructorRightContext DontDelete|ReadOnly
76 $' regExpConstructorRightContext DontDelete|ReadOnly|DontEnum
77 $1 regExpConstructorDollar1 DontDelete|ReadOnly
78 $2 regExpConstructorDollar2 DontDelete|ReadOnly
79 $3 regExpConstructorDollar3 DontDelete|ReadOnly
80 $4 regExpConstructorDollar4 DontDelete|ReadOnly
81 $5 regExpConstructorDollar5 DontDelete|ReadOnly
82 $6 regExpConstructorDollar6 DontDelete|ReadOnly
83 $7 regExpConstructorDollar7 DontDelete|ReadOnly
84 $8 regExpConstructorDollar8 DontDelete|ReadOnly
85 $9 regExpConstructorDollar9 DontDelete|ReadOnly
86 @end
87 */
88
89 RegExpConstructor::RegExpConstructor(JSGlobalObject* globalObject, Structure* structure, RegExpPrototype* regExpPrototype)
90 : InternalFunction(globalObject, structure)
91 , m_cachedResult(globalObject->vm(), this, regExpPrototype->regExp())
92 , m_multiline(false)
93 {
94 }
95
96 void RegExpConstructor::finishCreation(ExecState* exec, RegExpPrototype* regExpPrototype)
97 {
98 Base::finishCreation(exec->vm(), Identifier(exec, "RegExp").string());
99 ASSERT(inherits(&s_info));
100
101 // ECMA 15.10.5.1 RegExp.prototype
102 putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly);
103
104 // no. of arguments for constructor
105 putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(2), ReadOnly | DontDelete | DontEnum);
106 }
107
108 void RegExpConstructor::destroy(JSCell* cell)
109 {
110 static_cast<RegExpConstructor*>(cell)->RegExpConstructor::~RegExpConstructor();
111 }
112
113 void RegExpConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor)
114 {
115 RegExpConstructor* thisObject = jsCast<RegExpConstructor*>(cell);
116 ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
117 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
118 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
119
120 Base::visitChildren(thisObject, visitor);
121 thisObject->m_cachedResult.visitChildren(visitor);
122 }
123
124 JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i)
125 {
126 RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this);
127
128 if (i < array->length()) {
129 JSValue result = JSValue(array).get(exec, i);
130 ASSERT(result.isString() || result.isUndefined());
131 if (!result.isUndefined())
132 return result;
133 }
134 return jsEmptyString(exec);
135 }
136
137 JSValue RegExpConstructor::getLastParen(ExecState* exec)
138 {
139 RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this);
140 unsigned length = array->length();
141 if (length > 1) {
142 JSValue result = JSValue(array).get(exec, length - 1);
143 ASSERT(result.isString() || result.isUndefined());
144 if (!result.isUndefined())
145 return result;
146 }
147 return jsEmptyString(exec);
148 }
149
150 JSValue RegExpConstructor::getLeftContext(ExecState* exec)
151 {
152 return m_cachedResult.lastResult(exec, this)->leftContext(exec);
153 }
154
155 JSValue RegExpConstructor::getRightContext(ExecState* exec)
156 {
157 return m_cachedResult.lastResult(exec, this)->rightContext(exec);
158 }
159
160 bool RegExpConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
161 {
162 return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), jsCast<RegExpConstructor*>(cell), propertyName, slot);
163 }
164
165 bool RegExpConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
166 {
167 return getStaticValueDescriptor<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), jsCast<RegExpConstructor*>(object), propertyName, descriptor);
168 }
169
170 JSValue regExpConstructorDollar1(ExecState* exec, JSValue slotBase, PropertyName)
171 {
172 return asRegExpConstructor(slotBase)->getBackref(exec, 1);
173 }
174
175 JSValue regExpConstructorDollar2(ExecState* exec, JSValue slotBase, PropertyName)
176 {
177 return asRegExpConstructor(slotBase)->getBackref(exec, 2);
178 }
179
180 JSValue regExpConstructorDollar3(ExecState* exec, JSValue slotBase, PropertyName)
181 {
182 return asRegExpConstructor(slotBase)->getBackref(exec, 3);
183 }
184
185 JSValue regExpConstructorDollar4(ExecState* exec, JSValue slotBase, PropertyName)
186 {
187 return asRegExpConstructor(slotBase)->getBackref(exec, 4);
188 }
189
190 JSValue regExpConstructorDollar5(ExecState* exec, JSValue slotBase, PropertyName)
191 {
192 return asRegExpConstructor(slotBase)->getBackref(exec, 5);
193 }
194
195 JSValue regExpConstructorDollar6(ExecState* exec, JSValue slotBase, PropertyName)
196 {
197 return asRegExpConstructor(slotBase)->getBackref(exec, 6);
198 }
199
200 JSValue regExpConstructorDollar7(ExecState* exec, JSValue slotBase, PropertyName)
201 {
202 return asRegExpConstructor(slotBase)->getBackref(exec, 7);
203 }
204
205 JSValue regExpConstructorDollar8(ExecState* exec, JSValue slotBase, PropertyName)
206 {
207 return asRegExpConstructor(slotBase)->getBackref(exec, 8);
208 }
209
210 JSValue regExpConstructorDollar9(ExecState* exec, JSValue slotBase, PropertyName)
211 {
212 return asRegExpConstructor(slotBase)->getBackref(exec, 9);
213 }
214
215 JSValue regExpConstructorInput(ExecState*, JSValue slotBase, PropertyName)
216 {
217 return asRegExpConstructor(slotBase)->input();
218 }
219
220 JSValue regExpConstructorMultiline(ExecState*, JSValue slotBase, PropertyName)
221 {
222 return jsBoolean(asRegExpConstructor(slotBase)->multiline());
223 }
224
225 JSValue regExpConstructorLastMatch(ExecState* exec, JSValue slotBase, PropertyName)
226 {
227 return asRegExpConstructor(slotBase)->getBackref(exec, 0);
228 }
229
230 JSValue regExpConstructorLastParen(ExecState* exec, JSValue slotBase, PropertyName)
231 {
232 return asRegExpConstructor(slotBase)->getLastParen(exec);
233 }
234
235 JSValue regExpConstructorLeftContext(ExecState* exec, JSValue slotBase, PropertyName)
236 {
237 return asRegExpConstructor(slotBase)->getLeftContext(exec);
238 }
239
240 JSValue regExpConstructorRightContext(ExecState* exec, JSValue slotBase, PropertyName)
241 {
242 return asRegExpConstructor(slotBase)->getRightContext(exec);
243 }
244
245 void RegExpConstructor::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
246 {
247 lookupPut<RegExpConstructor, InternalFunction>(exec, propertyName, value, ExecState::regExpConstructorTable(exec), jsCast<RegExpConstructor*>(cell), slot);
248 }
249
250 void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValue value)
251 {
252 asRegExpConstructor(baseObject)->setInput(exec, value.toString(exec));
253 }
254
255 void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValue value)
256 {
257 asRegExpConstructor(baseObject)->setMultiline(value.toBoolean(exec));
258 }
259
260 // ECMA 15.10.4
261 JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, bool callAsConstructor)
262 {
263 JSValue arg0 = args.at(0);
264 JSValue arg1 = args.at(1);
265
266 if (arg0.inherits(&RegExpObject::s_info)) {
267 if (!arg1.isUndefined())
268 return throwError(exec, createTypeError(exec, ASCIILiteral("Cannot supply flags when constructing one RegExp from another.")));
269 // If called as a function, this just returns the first argument (see 15.10.3.1).
270 if (callAsConstructor) {
271 RegExp* regExp = static_cast<RegExpObject*>(asObject(arg0))->regExp();
272 return RegExpObject::create(exec, globalObject, globalObject->regExpStructure(), regExp);
273 }
274 return asObject(arg0);
275 }
276
277 String pattern = arg0.isUndefined() ? String("") : arg0.toString(exec)->value(exec);
278 if (exec->hadException())
279 return 0;
280
281 RegExpFlags flags = NoFlags;
282 if (!arg1.isUndefined()) {
283 flags = regExpFlags(arg1.toString(exec)->value(exec));
284 if (exec->hadException())
285 return 0;
286 if (flags == InvalidFlags)
287 return throwError(exec, createSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor.")));
288 }
289
290 RegExp* regExp = RegExp::create(exec->vm(), pattern, flags);
291 if (!regExp->isValid())
292 return throwError(exec, createSyntaxError(exec, regExp->errorMessage()));
293 return RegExpObject::create(exec, exec->lexicalGlobalObject(), globalObject->regExpStructure(), regExp);
294 }
295
296 static EncodedJSValue JSC_HOST_CALL constructWithRegExpConstructor(ExecState* exec)
297 {
298 ArgList args(exec);
299 return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, true));
300 }
301
302 ConstructType RegExpConstructor::getConstructData(JSCell*, ConstructData& constructData)
303 {
304 constructData.native.function = constructWithRegExpConstructor;
305 return ConstructTypeHost;
306 }
307
308 // ECMA 15.10.3
309 static EncodedJSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec)
310 {
311 ArgList args(exec);
312 return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args));
313 }
314
315 CallType RegExpConstructor::getCallData(JSCell*, CallData& callData)
316 {
317 callData.native.function = callRegExpConstructor;
318 return CallTypeHost;
319 }
320
321 } // namespace JSC