Source/JavaScriptCore: https://bugs.webkit.org/show_bug.cgi?id=119548
[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 "Operations.h"
27 #include "RegExpMatchesArray.h"
28 #include "RegExpPrototype.h"
29
30 namespace JSC {
31
32 static JSValue regExpConstructorInput(ExecState*, JSValue, PropertyName);
33 static JSValue regExpConstructorMultiline(ExecState*, JSValue, PropertyName);
34 static JSValue regExpConstructorLastMatch(ExecState*, JSValue, PropertyName);
35 static JSValue regExpConstructorLastParen(ExecState*, JSValue, PropertyName);
36 static JSValue regExpConstructorLeftContext(ExecState*, JSValue, PropertyName);
37 static JSValue regExpConstructorRightContext(ExecState*, JSValue, PropertyName);
38 static JSValue regExpConstructorDollar1(ExecState*, JSValue, PropertyName);
39 static JSValue regExpConstructorDollar2(ExecState*, JSValue, PropertyName);
40 static JSValue regExpConstructorDollar3(ExecState*, JSValue, PropertyName);
41 static JSValue regExpConstructorDollar4(ExecState*, JSValue, PropertyName);
42 static JSValue regExpConstructorDollar5(ExecState*, JSValue, PropertyName);
43 static JSValue regExpConstructorDollar6(ExecState*, JSValue, PropertyName);
44 static JSValue regExpConstructorDollar7(ExecState*, JSValue, PropertyName);
45 static JSValue regExpConstructorDollar8(ExecState*, JSValue, PropertyName);
46 static JSValue regExpConstructorDollar9(ExecState*, JSValue, PropertyName);
47
48 static void setRegExpConstructorInput(ExecState*, JSObject*, JSValue);
49 static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValue);
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(JSGlobalObject* globalObject, Structure* structure, RegExpPrototype* regExpPrototype)
86     : InternalFunction(globalObject, structure)
87     , m_cachedResult(globalObject->vm(), this, regExpPrototype->regExp())
88     , m_multiline(false)
89 {
90 }
91
92 void RegExpConstructor::finishCreation(ExecState* exec, RegExpPrototype* regExpPrototype)
93 {
94     Base::finishCreation(exec->vm(), Identifier(exec, "RegExp").string());
95     ASSERT(inherits(info()));
96
97     // ECMA 15.10.5.1 RegExp.prototype
98     putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly);
99
100     // no. of arguments for constructor
101     putDirectWithoutTransition(exec->vm(), exec->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), jsCast<RegExpConstructor*>(object), propertyName, slot);
159 }
160
161 JSValue regExpConstructorDollar1(ExecState* exec, JSValue slotBase, PropertyName)
162 {
163     return asRegExpConstructor(slotBase)->getBackref(exec, 1);
164 }
165
166 JSValue regExpConstructorDollar2(ExecState* exec, JSValue slotBase, PropertyName)
167 {
168     return asRegExpConstructor(slotBase)->getBackref(exec, 2);
169 }
170
171 JSValue regExpConstructorDollar3(ExecState* exec, JSValue slotBase, PropertyName)
172 {
173     return asRegExpConstructor(slotBase)->getBackref(exec, 3);
174 }
175
176 JSValue regExpConstructorDollar4(ExecState* exec, JSValue slotBase, PropertyName)
177 {
178     return asRegExpConstructor(slotBase)->getBackref(exec, 4);
179 }
180
181 JSValue regExpConstructorDollar5(ExecState* exec, JSValue slotBase, PropertyName)
182 {
183     return asRegExpConstructor(slotBase)->getBackref(exec, 5);
184 }
185
186 JSValue regExpConstructorDollar6(ExecState* exec, JSValue slotBase, PropertyName)
187 {
188     return asRegExpConstructor(slotBase)->getBackref(exec, 6);
189 }
190
191 JSValue regExpConstructorDollar7(ExecState* exec, JSValue slotBase, PropertyName)
192 {
193     return asRegExpConstructor(slotBase)->getBackref(exec, 7);
194 }
195
196 JSValue regExpConstructorDollar8(ExecState* exec, JSValue slotBase, PropertyName)
197 {
198     return asRegExpConstructor(slotBase)->getBackref(exec, 8);
199 }
200
201 JSValue regExpConstructorDollar9(ExecState* exec, JSValue slotBase, PropertyName)
202 {
203     return asRegExpConstructor(slotBase)->getBackref(exec, 9);
204 }
205
206 JSValue regExpConstructorInput(ExecState*, JSValue slotBase, PropertyName)
207 {
208     return asRegExpConstructor(slotBase)->input();
209 }
210
211 JSValue regExpConstructorMultiline(ExecState*, JSValue slotBase, PropertyName)
212 {
213     return jsBoolean(asRegExpConstructor(slotBase)->multiline());
214 }
215
216 JSValue regExpConstructorLastMatch(ExecState* exec, JSValue slotBase, PropertyName)
217 {
218     return asRegExpConstructor(slotBase)->getBackref(exec, 0);
219 }
220
221 JSValue regExpConstructorLastParen(ExecState* exec, JSValue slotBase, PropertyName)
222 {
223     return asRegExpConstructor(slotBase)->getLastParen(exec);
224 }
225
226 JSValue regExpConstructorLeftContext(ExecState* exec, JSValue slotBase, PropertyName)
227 {
228     return asRegExpConstructor(slotBase)->getLeftContext(exec);
229 }
230
231 JSValue regExpConstructorRightContext(ExecState* exec, JSValue slotBase, PropertyName)
232 {
233     return asRegExpConstructor(slotBase)->getRightContext(exec);
234 }
235
236 void RegExpConstructor::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
237 {
238     lookupPut<RegExpConstructor, InternalFunction>(exec, propertyName, value, ExecState::regExpConstructorTable(exec), jsCast<RegExpConstructor*>(cell), slot);
239 }
240
241 void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValue value)
242 {
243     asRegExpConstructor(baseObject)->setInput(exec, value.toString(exec));
244 }
245
246 void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValue value)
247 {
248     asRegExpConstructor(baseObject)->setMultiline(value.toBoolean(exec));
249 }
250
251 // ECMA 15.10.4
252 JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, bool callAsConstructor)
253 {
254     JSValue arg0 = args.at(0);
255     JSValue arg1 = args.at(1);
256
257     if (arg0.inherits(RegExpObject::info())) {
258         if (!arg1.isUndefined())
259             return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Cannot supply flags when constructing one RegExp from another.")));
260         // If called as a function, this just returns the first argument (see 15.10.3.1).
261         if (callAsConstructor) {
262             RegExp* regExp = static_cast<RegExpObject*>(asObject(arg0))->regExp();
263             return RegExpObject::create(exec, globalObject, globalObject->regExpStructure(), regExp);
264         }
265         return asObject(arg0);
266     }
267
268     String pattern = arg0.isUndefined() ? emptyString() : arg0.toString(exec)->value(exec);
269     if (exec->hadException())
270         return 0;
271
272     RegExpFlags flags = NoFlags;
273     if (!arg1.isUndefined()) {
274         flags = regExpFlags(arg1.toString(exec)->value(exec));
275         if (exec->hadException())
276             return 0;
277         if (flags == InvalidFlags)
278             return exec->vm().throwException(exec, createSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor.")));
279     }
280
281     RegExp* regExp = RegExp::create(exec->vm(), pattern, flags);
282     if (!regExp->isValid())
283         return exec->vm().throwException(exec, createSyntaxError(exec, regExp->errorMessage()));
284     return RegExpObject::create(exec, exec->lexicalGlobalObject(), globalObject->regExpStructure(), regExp);
285 }
286
287 static EncodedJSValue JSC_HOST_CALL constructWithRegExpConstructor(ExecState* exec)
288 {
289     ArgList args(exec);
290     return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, true));
291 }
292
293 ConstructType RegExpConstructor::getConstructData(JSCell*, ConstructData& constructData)
294 {
295     constructData.native.function = constructWithRegExpConstructor;
296     return ConstructTypeHost;
297 }
298
299 // ECMA 15.10.3
300 static EncodedJSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec)
301 {
302     ArgList args(exec);
303     return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args));
304 }
305
306 CallType RegExpConstructor::getCallData(JSCell*, CallData& callData)
307 {
308     callData.native.function = callRegExpConstructor;
309     return CallTypeHost;
310 }
311
312 } // namespace JSC