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