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