]>
Commit | Line | Data |
---|---|---|
9dae56ea A |
1 | /* |
2 | * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) | |
3 | * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved. | |
ba379fdc | 4 | * Copyright (C) 2009 Torch Mobile, Inc. |
9dae56ea A |
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 | ||
f9bf01c6 | 25 | #include "Error.h" |
93a37866 | 26 | #include "Operations.h" |
9dae56ea | 27 | #include "RegExpMatchesArray.h" |
9dae56ea | 28 | #include "RegExpPrototype.h" |
14957cd0 | 29 | |
93a37866 | 30 | #if PLATFORM(IOS) |
14957cd0 | 31 | #include <wtf/PassOwnPtr.h> |
93a37866 | 32 | #endif |
9dae56ea A |
33 | |
34 | namespace JSC { | |
35 | ||
93a37866 A |
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); | |
ba379fdc A |
51 | |
52 | static void setRegExpConstructorInput(ExecState*, JSObject*, JSValue); | |
53 | static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValue); | |
9dae56ea A |
54 | |
55 | } // namespace JSC | |
56 | ||
57 | #include "RegExpConstructor.lut.h" | |
58 | ||
59 | namespace JSC { | |
60 | ||
6fe7ccc8 | 61 | const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::regExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) }; |
9dae56ea A |
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 | ||
6fe7ccc8 A |
89 | RegExpConstructor::RegExpConstructor(JSGlobalObject* globalObject, Structure* structure, RegExpPrototype* regExpPrototype) |
90 | : InternalFunction(globalObject, structure) | |
93a37866 | 91 | , m_cachedResult(globalObject->vm(), this, regExpPrototype->regExp()) |
6fe7ccc8 A |
92 | , m_multiline(false) |
93 | { | |
94 | } | |
95 | ||
96 | void RegExpConstructor::finishCreation(ExecState* exec, RegExpPrototype* regExpPrototype) | |
9dae56ea | 97 | { |
93a37866 | 98 | Base::finishCreation(exec->vm(), Identifier(exec, "RegExp").string()); |
14957cd0 A |
99 | ASSERT(inherits(&s_info)); |
100 | ||
9dae56ea | 101 | // ECMA 15.10.5.1 RegExp.prototype |
93a37866 | 102 | putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly); |
9dae56ea A |
103 | |
104 | // no. of arguments for constructor | |
93a37866 | 105 | putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(2), ReadOnly | DontDelete | DontEnum); |
9dae56ea A |
106 | } |
107 | ||
6fe7ccc8 | 108 | void RegExpConstructor::destroy(JSCell* cell) |
9dae56ea | 109 | { |
93a37866 | 110 | static_cast<RegExpConstructor*>(cell)->RegExpConstructor::~RegExpConstructor(); |
9dae56ea A |
111 | } |
112 | ||
6fe7ccc8 | 113 | void RegExpConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor) |
9dae56ea | 114 | { |
6fe7ccc8 A |
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()); | |
9dae56ea | 119 | |
6fe7ccc8 A |
120 | Base::visitChildren(thisObject, visitor); |
121 | thisObject->m_cachedResult.visitChildren(visitor); | |
9dae56ea A |
122 | } |
123 | ||
6fe7ccc8 | 124 | JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) |
9dae56ea | 125 | { |
6fe7ccc8 | 126 | RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this); |
9dae56ea | 127 | |
6fe7ccc8 A |
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; | |
9dae56ea A |
133 | } |
134 | return jsEmptyString(exec); | |
135 | } | |
136 | ||
6fe7ccc8 | 137 | JSValue RegExpConstructor::getLastParen(ExecState* exec) |
9dae56ea | 138 | { |
6fe7ccc8 A |
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; | |
9dae56ea A |
146 | } |
147 | return jsEmptyString(exec); | |
148 | } | |
149 | ||
6fe7ccc8 | 150 | JSValue RegExpConstructor::getLeftContext(ExecState* exec) |
9dae56ea | 151 | { |
6fe7ccc8 | 152 | return m_cachedResult.lastResult(exec, this)->leftContext(exec); |
9dae56ea A |
153 | } |
154 | ||
6fe7ccc8 | 155 | JSValue RegExpConstructor::getRightContext(ExecState* exec) |
9dae56ea | 156 | { |
6fe7ccc8 | 157 | return m_cachedResult.lastResult(exec, this)->rightContext(exec); |
9dae56ea A |
158 | } |
159 | ||
93a37866 | 160 | bool RegExpConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) |
9dae56ea | 161 | { |
6fe7ccc8 | 162 | return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), jsCast<RegExpConstructor*>(cell), propertyName, slot); |
9dae56ea A |
163 | } |
164 | ||
93a37866 | 165 | bool RegExpConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) |
f9bf01c6 | 166 | { |
6fe7ccc8 | 167 | return getStaticValueDescriptor<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), jsCast<RegExpConstructor*>(object), propertyName, descriptor); |
f9bf01c6 A |
168 | } |
169 | ||
93a37866 | 170 | JSValue regExpConstructorDollar1(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 171 | { |
4e4e5a6f | 172 | return asRegExpConstructor(slotBase)->getBackref(exec, 1); |
9dae56ea A |
173 | } |
174 | ||
93a37866 | 175 | JSValue regExpConstructorDollar2(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 176 | { |
4e4e5a6f | 177 | return asRegExpConstructor(slotBase)->getBackref(exec, 2); |
9dae56ea A |
178 | } |
179 | ||
93a37866 | 180 | JSValue regExpConstructorDollar3(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 181 | { |
4e4e5a6f | 182 | return asRegExpConstructor(slotBase)->getBackref(exec, 3); |
9dae56ea A |
183 | } |
184 | ||
93a37866 | 185 | JSValue regExpConstructorDollar4(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 186 | { |
4e4e5a6f | 187 | return asRegExpConstructor(slotBase)->getBackref(exec, 4); |
9dae56ea A |
188 | } |
189 | ||
93a37866 | 190 | JSValue regExpConstructorDollar5(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 191 | { |
4e4e5a6f | 192 | return asRegExpConstructor(slotBase)->getBackref(exec, 5); |
9dae56ea A |
193 | } |
194 | ||
93a37866 | 195 | JSValue regExpConstructorDollar6(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 196 | { |
4e4e5a6f | 197 | return asRegExpConstructor(slotBase)->getBackref(exec, 6); |
9dae56ea A |
198 | } |
199 | ||
93a37866 | 200 | JSValue regExpConstructorDollar7(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 201 | { |
4e4e5a6f | 202 | return asRegExpConstructor(slotBase)->getBackref(exec, 7); |
9dae56ea A |
203 | } |
204 | ||
93a37866 | 205 | JSValue regExpConstructorDollar8(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 206 | { |
4e4e5a6f | 207 | return asRegExpConstructor(slotBase)->getBackref(exec, 8); |
9dae56ea A |
208 | } |
209 | ||
93a37866 | 210 | JSValue regExpConstructorDollar9(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 211 | { |
4e4e5a6f | 212 | return asRegExpConstructor(slotBase)->getBackref(exec, 9); |
9dae56ea A |
213 | } |
214 | ||
93a37866 | 215 | JSValue regExpConstructorInput(ExecState*, JSValue slotBase, PropertyName) |
9dae56ea | 216 | { |
6fe7ccc8 | 217 | return asRegExpConstructor(slotBase)->input(); |
9dae56ea A |
218 | } |
219 | ||
93a37866 | 220 | JSValue regExpConstructorMultiline(ExecState*, JSValue slotBase, PropertyName) |
9dae56ea | 221 | { |
4e4e5a6f | 222 | return jsBoolean(asRegExpConstructor(slotBase)->multiline()); |
9dae56ea A |
223 | } |
224 | ||
93a37866 | 225 | JSValue regExpConstructorLastMatch(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 226 | { |
4e4e5a6f | 227 | return asRegExpConstructor(slotBase)->getBackref(exec, 0); |
9dae56ea A |
228 | } |
229 | ||
93a37866 | 230 | JSValue regExpConstructorLastParen(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 231 | { |
4e4e5a6f | 232 | return asRegExpConstructor(slotBase)->getLastParen(exec); |
9dae56ea A |
233 | } |
234 | ||
93a37866 | 235 | JSValue regExpConstructorLeftContext(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 236 | { |
4e4e5a6f | 237 | return asRegExpConstructor(slotBase)->getLeftContext(exec); |
9dae56ea A |
238 | } |
239 | ||
93a37866 | 240 | JSValue regExpConstructorRightContext(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 241 | { |
4e4e5a6f | 242 | return asRegExpConstructor(slotBase)->getRightContext(exec); |
9dae56ea A |
243 | } |
244 | ||
93a37866 | 245 | void RegExpConstructor::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) |
9dae56ea | 246 | { |
6fe7ccc8 | 247 | lookupPut<RegExpConstructor, InternalFunction>(exec, propertyName, value, ExecState::regExpConstructorTable(exec), jsCast<RegExpConstructor*>(cell), slot); |
9dae56ea A |
248 | } |
249 | ||
ba379fdc | 250 | void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValue value) |
9dae56ea | 251 | { |
6fe7ccc8 | 252 | asRegExpConstructor(baseObject)->setInput(exec, value.toString(exec)); |
9dae56ea A |
253 | } |
254 | ||
ba379fdc | 255 | void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValue value) |
9dae56ea A |
256 | { |
257 | asRegExpConstructor(baseObject)->setMultiline(value.toBoolean(exec)); | |
258 | } | |
14957cd0 | 259 | |
9dae56ea | 260 | // ECMA 15.10.4 |
6fe7ccc8 | 261 | JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, bool callAsConstructor) |
9dae56ea | 262 | { |
ba379fdc A |
263 | JSValue arg0 = args.at(0); |
264 | JSValue arg1 = args.at(1); | |
9dae56ea | 265 | |
14957cd0 | 266 | if (arg0.inherits(&RegExpObject::s_info)) { |
9dae56ea | 267 | if (!arg1.isUndefined()) |
93a37866 | 268 | return throwError(exec, createTypeError(exec, ASCIILiteral("Cannot supply flags when constructing one RegExp from another."))); |
6fe7ccc8 A |
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 | } | |
9dae56ea A |
274 | return asObject(arg0); |
275 | } | |
276 | ||
93a37866 | 277 | String pattern = arg0.isUndefined() ? String("") : arg0.toString(exec)->value(exec); |
14957cd0 A |
278 | if (exec->hadException()) |
279 | return 0; | |
280 | ||
281 | RegExpFlags flags = NoFlags; | |
282 | if (!arg1.isUndefined()) { | |
6fe7ccc8 | 283 | flags = regExpFlags(arg1.toString(exec)->value(exec)); |
14957cd0 A |
284 | if (exec->hadException()) |
285 | return 0; | |
286 | if (flags == InvalidFlags) | |
93a37866 | 287 | return throwError(exec, createSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor."))); |
14957cd0 | 288 | } |
9dae56ea | 289 | |
93a37866 | 290 | RegExp* regExp = RegExp::create(exec->vm(), pattern, flags); |
9dae56ea | 291 | if (!regExp->isValid()) |
14957cd0 | 292 | return throwError(exec, createSyntaxError(exec, regExp->errorMessage())); |
6fe7ccc8 | 293 | return RegExpObject::create(exec, exec->lexicalGlobalObject(), globalObject->regExpStructure(), regExp); |
9dae56ea A |
294 | } |
295 | ||
14957cd0 | 296 | static EncodedJSValue JSC_HOST_CALL constructWithRegExpConstructor(ExecState* exec) |
9dae56ea | 297 | { |
14957cd0 | 298 | ArgList args(exec); |
6fe7ccc8 | 299 | return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, true)); |
9dae56ea A |
300 | } |
301 | ||
6fe7ccc8 | 302 | ConstructType RegExpConstructor::getConstructData(JSCell*, ConstructData& constructData) |
9dae56ea A |
303 | { |
304 | constructData.native.function = constructWithRegExpConstructor; | |
305 | return ConstructTypeHost; | |
306 | } | |
307 | ||
308 | // ECMA 15.10.3 | |
14957cd0 | 309 | static EncodedJSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec) |
9dae56ea | 310 | { |
14957cd0 A |
311 | ArgList args(exec); |
312 | return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args)); | |
9dae56ea A |
313 | } |
314 | ||
6fe7ccc8 | 315 | CallType RegExpConstructor::getCallData(JSCell*, CallData& callData) |
9dae56ea A |
316 | { |
317 | callData.native.function = callRegExpConstructor; | |
318 | return CallTypeHost; | |
319 | } | |
320 | ||
9dae56ea | 321 | } // namespace JSC |