Remove a bunch of unnecessary includes
[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, 2016 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 "GetterSetter.h"
27 #include "JSCInlines.h"
28 #include "RegExpPrototype.h"
29 #include "StructureInlines.h"
30
31 namespace JSC {
32
33 static EncodedJSValue regExpConstructorInput(ExecState*, EncodedJSValue, PropertyName);
34 static EncodedJSValue regExpConstructorMultiline(ExecState*, EncodedJSValue, PropertyName);
35 static EncodedJSValue regExpConstructorLastMatch(ExecState*, EncodedJSValue, PropertyName);
36 static EncodedJSValue regExpConstructorLastParen(ExecState*, EncodedJSValue, PropertyName);
37 static EncodedJSValue regExpConstructorLeftContext(ExecState*, EncodedJSValue, PropertyName);
38 static EncodedJSValue regExpConstructorRightContext(ExecState*, EncodedJSValue, PropertyName);
39 template<int N>
40 static EncodedJSValue regExpConstructorDollar(ExecState*, EncodedJSValue, PropertyName);
41
42 static bool setRegExpConstructorInput(ExecState*, EncodedJSValue, EncodedJSValue);
43 static bool setRegExpConstructorMultiline(ExecState*, EncodedJSValue, EncodedJSValue);
44
45 } // namespace JSC
46
47 #include "RegExpConstructor.lut.h"
48
49 namespace JSC {
50
51 const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, &regExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) };
52
53 /* Source for RegExpConstructor.lut.h
54 @begin regExpConstructorTable
55     input           regExpConstructorInput          None
56     $_              regExpConstructorInput          DontEnum
57     multiline       regExpConstructorMultiline      None
58     $*              regExpConstructorMultiline      DontEnum
59     lastMatch       regExpConstructorLastMatch      DontDelete|ReadOnly
60     $&              regExpConstructorLastMatch      DontDelete|ReadOnly|DontEnum
61     lastParen       regExpConstructorLastParen      DontDelete|ReadOnly
62     $+              regExpConstructorLastParen      DontDelete|ReadOnly|DontEnum
63     leftContext     regExpConstructorLeftContext    DontDelete|ReadOnly
64     $`              regExpConstructorLeftContext    DontDelete|ReadOnly|DontEnum
65     rightContext    regExpConstructorRightContext   DontDelete|ReadOnly
66     $'              regExpConstructorRightContext   DontDelete|ReadOnly|DontEnum
67     $1              regExpConstructorDollar<1>      DontDelete|ReadOnly
68     $2              regExpConstructorDollar<2>      DontDelete|ReadOnly
69     $3              regExpConstructorDollar<3>      DontDelete|ReadOnly
70     $4              regExpConstructorDollar<4>      DontDelete|ReadOnly
71     $5              regExpConstructorDollar<5>      DontDelete|ReadOnly
72     $6              regExpConstructorDollar<6>      DontDelete|ReadOnly
73     $7              regExpConstructorDollar<7>      DontDelete|ReadOnly
74     $8              regExpConstructorDollar<8>      DontDelete|ReadOnly
75     $9              regExpConstructorDollar<9>      DontDelete|ReadOnly
76 @end
77 */
78
79 RegExpConstructor::RegExpConstructor(VM& vm, Structure* structure, RegExpPrototype* regExpPrototype)
80     : InternalFunction(vm, structure)
81     , m_cachedResult(vm, this, regExpPrototype->emptyRegExp())
82     , m_multiline(false)
83 {
84 }
85
86 void RegExpConstructor::finishCreation(VM& vm, RegExpPrototype* regExpPrototype, GetterSetter* speciesSymbol)
87 {
88     Base::finishCreation(vm, ASCIILiteral("RegExp"));
89     ASSERT(inherits(info()));
90
91     putDirectWithoutTransition(vm, vm.propertyNames->prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly);
92
93     // no. of arguments for constructor
94     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(2), ReadOnly | DontDelete | DontEnum);
95
96     putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, Accessor | ReadOnly | DontEnum);
97 }
98
99 void RegExpConstructor::destroy(JSCell* cell)
100 {
101     static_cast<RegExpConstructor*>(cell)->RegExpConstructor::~RegExpConstructor();
102 }
103
104 void RegExpConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor)
105 {
106     RegExpConstructor* thisObject = jsCast<RegExpConstructor*>(cell);
107     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
108     Base::visitChildren(thisObject, visitor);
109     thisObject->m_cachedResult.visitChildren(visitor);
110 }
111
112 JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i)
113 {
114     JSArray* array = m_cachedResult.lastResult(exec, this);
115
116     if (i < array->length()) {
117         JSValue result = JSValue(array).get(exec, i);
118         ASSERT(result.isString() || result.isUndefined());
119         if (!result.isUndefined())
120             return result;
121     }
122     return jsEmptyString(exec);
123 }
124
125 JSValue RegExpConstructor::getLastParen(ExecState* exec)
126 {
127     JSArray* array = m_cachedResult.lastResult(exec, this);
128     unsigned length = array->length();
129     if (length > 1) {
130         JSValue result = JSValue(array).get(exec, length - 1);
131         ASSERT(result.isString() || result.isUndefined());
132         if (!result.isUndefined())
133             return result;
134     }
135     return jsEmptyString(exec);
136 }
137
138 JSValue RegExpConstructor::getLeftContext(ExecState* exec)
139 {
140     return m_cachedResult.leftContext(exec, this);
141 }
142
143 JSValue RegExpConstructor::getRightContext(ExecState* exec)
144 {
145     return m_cachedResult.rightContext(exec, this);
146 }
147
148 template<int N>
149 EncodedJSValue regExpConstructorDollar(ExecState* exec, EncodedJSValue thisValue, PropertyName)
150 {
151     return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, N));
152 }
153
154 EncodedJSValue regExpConstructorInput(ExecState*, EncodedJSValue thisValue, PropertyName)
155 {
156     return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->input());
157 }
158
159 EncodedJSValue regExpConstructorMultiline(ExecState*, EncodedJSValue thisValue, PropertyName)
160 {
161     return JSValue::encode(jsBoolean(asRegExpConstructor(JSValue::decode(thisValue))->multiline()));
162 }
163
164 EncodedJSValue regExpConstructorLastMatch(ExecState* exec, EncodedJSValue thisValue, PropertyName)
165 {
166     return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, 0));
167 }
168
169 EncodedJSValue regExpConstructorLastParen(ExecState* exec, EncodedJSValue thisValue, PropertyName)
170 {
171     return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getLastParen(exec));
172 }
173
174 EncodedJSValue regExpConstructorLeftContext(ExecState* exec, EncodedJSValue thisValue, PropertyName)
175 {
176     return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getLeftContext(exec));
177 }
178
179 EncodedJSValue regExpConstructorRightContext(ExecState* exec, EncodedJSValue thisValue, PropertyName)
180 {
181     return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getRightContext(exec));
182 }
183
184 bool setRegExpConstructorInput(ExecState* exec, EncodedJSValue thisValue, EncodedJSValue value)
185 {
186     if (auto constructor = jsDynamicCast<RegExpConstructor*>(JSValue::decode(thisValue))) {
187         constructor->setInput(exec, JSValue::decode(value).toString(exec));
188         return true;
189     }
190     return false;
191 }
192
193 bool setRegExpConstructorMultiline(ExecState* exec, EncodedJSValue thisValue, EncodedJSValue value)
194 {
195     if (auto constructor = jsDynamicCast<RegExpConstructor*>(JSValue::decode(thisValue))) {
196         constructor->setMultiline(JSValue::decode(value).toBoolean(exec));
197         return true;
198     }
199     return false;
200 }
201
202 inline Structure* getRegExpStructure(ExecState* exec, JSGlobalObject* globalObject, JSValue newTarget)
203 {
204     Structure* structure = globalObject->regExpStructure();
205     if (newTarget != jsUndefined())
206         structure = InternalFunction::createSubclassStructure(exec, newTarget, structure);
207     return structure;
208 }
209
210 inline RegExpFlags toFlags(ExecState* exec, JSValue flags)
211 {
212     VM& vm = exec->vm();
213     auto scope = DECLARE_THROW_SCOPE(vm);
214
215     if (flags.isUndefined())
216         return NoFlags;
217     JSString* flagsString = flags.toString(exec);
218     ASSERT(scope.exception() || flagsString);
219     if (!flagsString) {
220         return InvalidFlags;
221     }
222
223     RegExpFlags result = regExpFlags(flagsString->value(exec));
224     if (UNLIKELY(scope.exception()))
225         return InvalidFlags;
226     if (result == InvalidFlags)
227         throwSyntaxError(exec, scope, ASCIILiteral("Invalid flags supplied to RegExp constructor."));
228     return result;
229 }
230
231 static JSObject* regExpCreate(ExecState* exec, JSGlobalObject* globalObject, JSValue newTarget, JSValue patternArg, JSValue flagsArg)
232 {
233     VM& vm = exec->vm();
234     auto scope = DECLARE_THROW_SCOPE(vm);
235
236     String pattern = patternArg.isUndefined() ? emptyString() : patternArg.toString(exec)->value(exec);
237     if (UNLIKELY(scope.exception()))
238         return nullptr;
239
240     RegExpFlags flags = toFlags(exec, flagsArg);
241     if (flags == InvalidFlags)
242         return nullptr;
243
244     RegExp* regExp = RegExp::create(vm, pattern, flags);
245     if (!regExp->isValid())
246         return throwException(exec, scope, createSyntaxError(exec, regExp->errorMessage()));
247
248     Structure* structure = getRegExpStructure(exec, globalObject, newTarget);
249     if (UNLIKELY(scope.exception()))
250         return nullptr;
251     return RegExpObject::create(vm, structure, regExp);
252 }
253
254 JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args,  JSObject* callee, JSValue newTarget)
255 {
256     VM& vm = exec->vm();
257     auto scope = DECLARE_THROW_SCOPE(vm);
258     JSValue patternArg = args.at(0);
259     JSValue flagsArg = args.at(1);
260
261     bool isPatternRegExp = patternArg.inherits(RegExpObject::info());
262     bool constructAsRegexp = isRegExp(vm, exec, patternArg);
263
264     if (newTarget.isUndefined() && constructAsRegexp && flagsArg.isUndefined()) {
265         JSValue constructor = patternArg.get(exec, vm.propertyNames->constructor);
266         if (UNLIKELY(scope.exception()))
267             return nullptr;
268         if (callee == constructor) {
269             // We know that patternArg is a object otherwise constructAsRegexp would be false.
270             return patternArg.getObject();
271         }
272     }
273
274     if (isPatternRegExp) {
275         RegExp* regExp = jsCast<RegExpObject*>(patternArg)->regExp();
276         Structure* structure = getRegExpStructure(exec, globalObject, newTarget);
277         if (UNLIKELY(scope.exception()))
278             return nullptr;
279
280         if (!flagsArg.isUndefined()) {
281             RegExpFlags flags = toFlags(exec, flagsArg);
282             if (flags == InvalidFlags)
283                 return nullptr;
284             regExp = RegExp::create(vm, regExp->pattern(), flags);
285         }
286
287         return RegExpObject::create(exec->vm(), structure, regExp);
288     }
289
290     if (constructAsRegexp) {
291         JSValue pattern = patternArg.get(exec, vm.propertyNames->source);
292         if (flagsArg.isUndefined())
293             flagsArg = patternArg.get(exec, vm.propertyNames->flags);
294         patternArg = pattern;
295     }
296
297     return regExpCreate(exec, globalObject, newTarget, patternArg, flagsArg);
298 }
299
300 EncodedJSValue JSC_HOST_CALL esSpecRegExpCreate(ExecState* exec)
301 {
302     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
303     JSValue patternArg = exec->argument(0);
304     JSValue flagsArg = exec->argument(1);
305     return JSValue::encode(regExpCreate(exec, globalObject, jsUndefined(), patternArg, flagsArg));
306 }
307
308 static EncodedJSValue JSC_HOST_CALL constructWithRegExpConstructor(ExecState* exec)
309 {
310     ArgList args(exec);
311     return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, exec->callee(), exec->newTarget()));
312 }
313
314 ConstructType RegExpConstructor::getConstructData(JSCell*, ConstructData& constructData)
315 {
316     constructData.native.function = constructWithRegExpConstructor;
317     return ConstructType::Host;
318 }
319
320 static EncodedJSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec)
321 {
322     ArgList args(exec);
323     return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, exec->callee()));
324 }
325
326 CallType RegExpConstructor::getCallData(JSCell*, CallData& callData)
327 {
328     callData.native.function = callRegExpConstructor;
329     return CallType::Host;
330 }
331
332 } // namespace JSC