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