]>
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" |
81345200 | 26 | #include "JSCInlines.h" |
9dae56ea | 27 | #include "RegExpMatchesArray.h" |
9dae56ea | 28 | #include "RegExpPrototype.h" |
14957cd0 | 29 | |
9dae56ea A |
30 | namespace JSC { |
31 | ||
81345200 A |
32 | static EncodedJSValue regExpConstructorInput(ExecState*, JSObject*, EncodedJSValue, PropertyName); |
33 | static EncodedJSValue regExpConstructorMultiline(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
34 | static EncodedJSValue regExpConstructorLastMatch(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
35 | static EncodedJSValue regExpConstructorLastParen(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
36 | static EncodedJSValue regExpConstructorLeftContext(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
37 | static EncodedJSValue regExpConstructorRightContext(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
38 | static EncodedJSValue regExpConstructorDollar1(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
39 | static EncodedJSValue regExpConstructorDollar2(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
40 | static EncodedJSValue regExpConstructorDollar3(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
41 | static EncodedJSValue regExpConstructorDollar4(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
42 | static EncodedJSValue regExpConstructorDollar5(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
43 | static EncodedJSValue regExpConstructorDollar6(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
44 | static EncodedJSValue regExpConstructorDollar7(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
45 | static EncodedJSValue regExpConstructorDollar8(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
46 | static EncodedJSValue regExpConstructorDollar9(ExecState*, JSObject*, EncodedJSValue, PropertyName); | |
47 | ||
48 | static void setRegExpConstructorInput(ExecState*, JSObject*, EncodedJSValue, EncodedJSValue); | |
49 | static void setRegExpConstructorMultiline(ExecState*, JSObject*, EncodedJSValue, EncodedJSValue); | |
9dae56ea A |
50 | |
51 | } // namespace JSC | |
52 | ||
53 | #include "RegExpConstructor.lut.h" | |
54 | ||
55 | namespace JSC { | |
56 | ||
6fe7ccc8 | 57 | const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::regExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) }; |
9dae56ea A |
58 | |
59 | /* Source for RegExpConstructor.lut.h | |
60 | @begin regExpConstructorTable | |
61 | input regExpConstructorInput None | |
62 | $_ regExpConstructorInput DontEnum | |
63 | multiline regExpConstructorMultiline None | |
64 | $* regExpConstructorMultiline DontEnum | |
65 | lastMatch regExpConstructorLastMatch DontDelete|ReadOnly | |
66 | $& regExpConstructorLastMatch DontDelete|ReadOnly|DontEnum | |
67 | lastParen regExpConstructorLastParen DontDelete|ReadOnly | |
68 | $+ regExpConstructorLastParen DontDelete|ReadOnly|DontEnum | |
69 | leftContext regExpConstructorLeftContext DontDelete|ReadOnly | |
70 | $` regExpConstructorLeftContext DontDelete|ReadOnly|DontEnum | |
71 | rightContext regExpConstructorRightContext DontDelete|ReadOnly | |
72 | $' regExpConstructorRightContext DontDelete|ReadOnly|DontEnum | |
73 | $1 regExpConstructorDollar1 DontDelete|ReadOnly | |
74 | $2 regExpConstructorDollar2 DontDelete|ReadOnly | |
75 | $3 regExpConstructorDollar3 DontDelete|ReadOnly | |
76 | $4 regExpConstructorDollar4 DontDelete|ReadOnly | |
77 | $5 regExpConstructorDollar5 DontDelete|ReadOnly | |
78 | $6 regExpConstructorDollar6 DontDelete|ReadOnly | |
79 | $7 regExpConstructorDollar7 DontDelete|ReadOnly | |
80 | $8 regExpConstructorDollar8 DontDelete|ReadOnly | |
81 | $9 regExpConstructorDollar9 DontDelete|ReadOnly | |
82 | @end | |
83 | */ | |
84 | ||
81345200 A |
85 | RegExpConstructor::RegExpConstructor(VM& vm, Structure* structure, RegExpPrototype* regExpPrototype) |
86 | : InternalFunction(vm, structure) | |
87 | , m_cachedResult(vm, this, regExpPrototype->regExp()) | |
6fe7ccc8 A |
88 | , m_multiline(false) |
89 | { | |
90 | } | |
91 | ||
81345200 | 92 | void RegExpConstructor::finishCreation(VM& vm, RegExpPrototype* regExpPrototype) |
9dae56ea | 93 | { |
81345200 A |
94 | Base::finishCreation(vm, Identifier(&vm, "RegExp").string()); |
95 | ASSERT(inherits(info())); | |
14957cd0 | 96 | |
9dae56ea | 97 | // ECMA 15.10.5.1 RegExp.prototype |
81345200 | 98 | putDirectWithoutTransition(vm, vm.propertyNames->prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly); |
9dae56ea A |
99 | |
100 | // no. of arguments for constructor | |
81345200 | 101 | putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(2), ReadOnly | DontDelete | DontEnum); |
9dae56ea A |
102 | } |
103 | ||
6fe7ccc8 | 104 | void RegExpConstructor::destroy(JSCell* cell) |
9dae56ea | 105 | { |
93a37866 | 106 | static_cast<RegExpConstructor*>(cell)->RegExpConstructor::~RegExpConstructor(); |
9dae56ea A |
107 | } |
108 | ||
6fe7ccc8 | 109 | void RegExpConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor) |
9dae56ea | 110 | { |
6fe7ccc8 | 111 | RegExpConstructor* thisObject = jsCast<RegExpConstructor*>(cell); |
81345200 | 112 | ASSERT_GC_OBJECT_INHERITS(thisObject, info()); |
6fe7ccc8 A |
113 | COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); |
114 | ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); | |
9dae56ea | 115 | |
6fe7ccc8 A |
116 | Base::visitChildren(thisObject, visitor); |
117 | thisObject->m_cachedResult.visitChildren(visitor); | |
9dae56ea A |
118 | } |
119 | ||
6fe7ccc8 | 120 | JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) |
9dae56ea | 121 | { |
6fe7ccc8 | 122 | RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this); |
9dae56ea | 123 | |
6fe7ccc8 A |
124 | if (i < array->length()) { |
125 | JSValue result = JSValue(array).get(exec, i); | |
126 | ASSERT(result.isString() || result.isUndefined()); | |
127 | if (!result.isUndefined()) | |
128 | return result; | |
9dae56ea A |
129 | } |
130 | return jsEmptyString(exec); | |
131 | } | |
132 | ||
6fe7ccc8 | 133 | JSValue RegExpConstructor::getLastParen(ExecState* exec) |
9dae56ea | 134 | { |
6fe7ccc8 A |
135 | RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this); |
136 | unsigned length = array->length(); | |
137 | if (length > 1) { | |
138 | JSValue result = JSValue(array).get(exec, length - 1); | |
139 | ASSERT(result.isString() || result.isUndefined()); | |
140 | if (!result.isUndefined()) | |
141 | return result; | |
9dae56ea A |
142 | } |
143 | return jsEmptyString(exec); | |
144 | } | |
145 | ||
6fe7ccc8 | 146 | JSValue RegExpConstructor::getLeftContext(ExecState* exec) |
9dae56ea | 147 | { |
6fe7ccc8 | 148 | return m_cachedResult.lastResult(exec, this)->leftContext(exec); |
9dae56ea A |
149 | } |
150 | ||
6fe7ccc8 | 151 | JSValue RegExpConstructor::getRightContext(ExecState* exec) |
9dae56ea | 152 | { |
6fe7ccc8 | 153 | return m_cachedResult.lastResult(exec, this)->rightContext(exec); |
9dae56ea A |
154 | } |
155 | ||
81345200 | 156 | bool RegExpConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) |
9dae56ea | 157 | { |
81345200 | 158 | return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec->vm()), jsCast<RegExpConstructor*>(object), propertyName, slot); |
9dae56ea | 159 | } |
81345200 A |
160 | |
161 | EncodedJSValue regExpConstructorDollar1(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) | |
9dae56ea | 162 | { |
81345200 | 163 | return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 1)); |
9dae56ea A |
164 | } |
165 | ||
81345200 | 166 | EncodedJSValue regExpConstructorDollar2(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 167 | { |
81345200 | 168 | return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 2)); |
9dae56ea A |
169 | } |
170 | ||
81345200 | 171 | EncodedJSValue regExpConstructorDollar3(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 172 | { |
81345200 | 173 | return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 3)); |
9dae56ea A |
174 | } |
175 | ||
81345200 | 176 | EncodedJSValue regExpConstructorDollar4(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 177 | { |
81345200 | 178 | return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 4)); |
9dae56ea A |
179 | } |
180 | ||
81345200 | 181 | EncodedJSValue regExpConstructorDollar5(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 182 | { |
81345200 | 183 | return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 5)); |
9dae56ea A |
184 | } |
185 | ||
81345200 | 186 | EncodedJSValue regExpConstructorDollar6(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 187 | { |
81345200 | 188 | return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 6)); |
9dae56ea A |
189 | } |
190 | ||
81345200 | 191 | EncodedJSValue regExpConstructorDollar7(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 192 | { |
81345200 | 193 | return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 7)); |
9dae56ea A |
194 | } |
195 | ||
81345200 | 196 | EncodedJSValue regExpConstructorDollar8(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 197 | { |
81345200 | 198 | return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 8)); |
9dae56ea A |
199 | } |
200 | ||
81345200 | 201 | EncodedJSValue regExpConstructorDollar9(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 202 | { |
81345200 | 203 | return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 9)); |
9dae56ea A |
204 | } |
205 | ||
81345200 | 206 | EncodedJSValue regExpConstructorInput(ExecState*, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 207 | { |
81345200 | 208 | return JSValue::encode(asRegExpConstructor(slotBase)->input()); |
9dae56ea A |
209 | } |
210 | ||
81345200 | 211 | EncodedJSValue regExpConstructorMultiline(ExecState*, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 212 | { |
81345200 | 213 | return JSValue::encode(jsBoolean(asRegExpConstructor(slotBase)->multiline())); |
9dae56ea A |
214 | } |
215 | ||
81345200 | 216 | EncodedJSValue regExpConstructorLastMatch(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 217 | { |
81345200 | 218 | return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 0)); |
9dae56ea A |
219 | } |
220 | ||
81345200 | 221 | EncodedJSValue regExpConstructorLastParen(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 222 | { |
81345200 | 223 | return JSValue::encode(asRegExpConstructor(slotBase)->getLastParen(exec)); |
9dae56ea A |
224 | } |
225 | ||
81345200 | 226 | EncodedJSValue regExpConstructorLeftContext(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 227 | { |
81345200 | 228 | return JSValue::encode(asRegExpConstructor(slotBase)->getLeftContext(exec)); |
9dae56ea A |
229 | } |
230 | ||
81345200 | 231 | EncodedJSValue regExpConstructorRightContext(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) |
9dae56ea | 232 | { |
81345200 | 233 | return JSValue::encode(asRegExpConstructor(slotBase)->getRightContext(exec)); |
9dae56ea A |
234 | } |
235 | ||
81345200 | 236 | void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, EncodedJSValue, EncodedJSValue value) |
9dae56ea | 237 | { |
81345200 A |
238 | if (auto constructor = jsDynamicCast<RegExpConstructor*>(baseObject)) |
239 | constructor->setInput(exec, JSValue::decode(value).toString(exec)); | |
9dae56ea A |
240 | } |
241 | ||
81345200 | 242 | void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, EncodedJSValue, EncodedJSValue value) |
9dae56ea | 243 | { |
81345200 A |
244 | if (auto constructor = jsDynamicCast<RegExpConstructor*>(baseObject)) |
245 | constructor->setMultiline(JSValue::decode(value).toBoolean(exec)); | |
9dae56ea | 246 | } |
14957cd0 | 247 | |
9dae56ea | 248 | // ECMA 15.10.4 |
6fe7ccc8 | 249 | JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, bool callAsConstructor) |
9dae56ea | 250 | { |
ba379fdc A |
251 | JSValue arg0 = args.at(0); |
252 | JSValue arg1 = args.at(1); | |
9dae56ea | 253 | |
81345200 | 254 | if (arg0.inherits(RegExpObject::info())) { |
9dae56ea | 255 | if (!arg1.isUndefined()) |
81345200 | 256 | return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Cannot supply flags when constructing one RegExp from another."))); |
6fe7ccc8 A |
257 | // If called as a function, this just returns the first argument (see 15.10.3.1). |
258 | if (callAsConstructor) { | |
259 | RegExp* regExp = static_cast<RegExpObject*>(asObject(arg0))->regExp(); | |
81345200 | 260 | return RegExpObject::create(exec->vm(), globalObject->regExpStructure(), regExp); |
6fe7ccc8 | 261 | } |
9dae56ea A |
262 | return asObject(arg0); |
263 | } | |
264 | ||
81345200 | 265 | String pattern = arg0.isUndefined() ? emptyString() : arg0.toString(exec)->value(exec); |
14957cd0 A |
266 | if (exec->hadException()) |
267 | return 0; | |
268 | ||
269 | RegExpFlags flags = NoFlags; | |
270 | if (!arg1.isUndefined()) { | |
6fe7ccc8 | 271 | flags = regExpFlags(arg1.toString(exec)->value(exec)); |
14957cd0 A |
272 | if (exec->hadException()) |
273 | return 0; | |
274 | if (flags == InvalidFlags) | |
81345200 | 275 | return exec->vm().throwException(exec, createSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor."))); |
14957cd0 | 276 | } |
9dae56ea | 277 | |
81345200 A |
278 | VM& vm = exec->vm(); |
279 | RegExp* regExp = RegExp::create(vm, pattern, flags); | |
9dae56ea | 280 | if (!regExp->isValid()) |
81345200 A |
281 | return vm.throwException(exec, createSyntaxError(exec, regExp->errorMessage())); |
282 | return RegExpObject::create(vm, globalObject->regExpStructure(), regExp); | |
9dae56ea A |
283 | } |
284 | ||
14957cd0 | 285 | static EncodedJSValue JSC_HOST_CALL constructWithRegExpConstructor(ExecState* exec) |
9dae56ea | 286 | { |
14957cd0 | 287 | ArgList args(exec); |
6fe7ccc8 | 288 | return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, true)); |
9dae56ea A |
289 | } |
290 | ||
6fe7ccc8 | 291 | ConstructType RegExpConstructor::getConstructData(JSCell*, ConstructData& constructData) |
9dae56ea A |
292 | { |
293 | constructData.native.function = constructWithRegExpConstructor; | |
294 | return ConstructTypeHost; | |
295 | } | |
296 | ||
297 | // ECMA 15.10.3 | |
14957cd0 | 298 | static EncodedJSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec) |
9dae56ea | 299 | { |
14957cd0 A |
300 | ArgList args(exec); |
301 | return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args)); | |
9dae56ea A |
302 | } |
303 | ||
6fe7ccc8 | 304 | CallType RegExpConstructor::getCallData(JSCell*, CallData& callData) |
9dae56ea A |
305 | { |
306 | callData.native.function = callRegExpConstructor; | |
307 | return CallTypeHost; | |
308 | } | |
309 | ||
9dae56ea | 310 | } // namespace JSC |