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 "ArrayPrototype.h"
26#include "Error.h"
27#include "JSArray.h"
28#include "JSFunction.h"
29#include "JSString.h"
30#include "ObjectPrototype.h"
31#include "RegExpMatchesArray.h"
32#include "RegExpObject.h"
33#include "RegExpPrototype.h"
34#include "RegExp.h"
35
36namespace JSC {
37
38static JSValue regExpConstructorInput(ExecState*, const Identifier&, const PropertySlot&);
39static JSValue regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot&);
40static JSValue regExpConstructorLastMatch(ExecState*, const Identifier&, const PropertySlot&);
41static JSValue regExpConstructorLastParen(ExecState*, const Identifier&, const PropertySlot&);
42static JSValue regExpConstructorLeftContext(ExecState*, const Identifier&, const PropertySlot&);
43static JSValue regExpConstructorRightContext(ExecState*, const Identifier&, const PropertySlot&);
44static JSValue regExpConstructorDollar1(ExecState*, const Identifier&, const PropertySlot&);
45static JSValue regExpConstructorDollar2(ExecState*, const Identifier&, const PropertySlot&);
46static JSValue regExpConstructorDollar3(ExecState*, const Identifier&, const PropertySlot&);
47static JSValue regExpConstructorDollar4(ExecState*, const Identifier&, const PropertySlot&);
48static JSValue regExpConstructorDollar5(ExecState*, const Identifier&, const PropertySlot&);
49static JSValue regExpConstructorDollar6(ExecState*, const Identifier&, const PropertySlot&);
50static JSValue regExpConstructorDollar7(ExecState*, const Identifier&, const PropertySlot&);
51static JSValue regExpConstructorDollar8(ExecState*, const Identifier&, const PropertySlot&);
52static JSValue regExpConstructorDollar9(ExecState*, const Identifier&, const PropertySlot&);
53
54static void setRegExpConstructorInput(ExecState*, JSObject*, JSValue);
55static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValue);
56
57} // namespace JSC
58
59#include "RegExpConstructor.lut.h"
60
61namespace JSC {
62
63ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor);
64
65const ClassInfo RegExpConstructor::info = { .className: "Function", .parentClass: &InternalFunction::info, .staticPropHashTable: 0, .classPropHashTableGetterFunction: ExecState::regExpConstructorTable };
66
67/* Source for RegExpConstructor.lut.h
68@begin regExpConstructorTable
69 input regExpConstructorInput None
70 $_ regExpConstructorInput DontEnum
71 multiline regExpConstructorMultiline None
72 $* regExpConstructorMultiline DontEnum
73 lastMatch regExpConstructorLastMatch DontDelete|ReadOnly
74 $& regExpConstructorLastMatch DontDelete|ReadOnly|DontEnum
75 lastParen regExpConstructorLastParen DontDelete|ReadOnly
76 $+ regExpConstructorLastParen DontDelete|ReadOnly|DontEnum
77 leftContext regExpConstructorLeftContext DontDelete|ReadOnly
78 $` regExpConstructorLeftContext DontDelete|ReadOnly|DontEnum
79 rightContext regExpConstructorRightContext DontDelete|ReadOnly
80 $' regExpConstructorRightContext DontDelete|ReadOnly|DontEnum
81 $1 regExpConstructorDollar1 DontDelete|ReadOnly
82 $2 regExpConstructorDollar2 DontDelete|ReadOnly
83 $3 regExpConstructorDollar3 DontDelete|ReadOnly
84 $4 regExpConstructorDollar4 DontDelete|ReadOnly
85 $5 regExpConstructorDollar5 DontDelete|ReadOnly
86 $6 regExpConstructorDollar6 DontDelete|ReadOnly
87 $7 regExpConstructorDollar7 DontDelete|ReadOnly
88 $8 regExpConstructorDollar8 DontDelete|ReadOnly
89 $9 regExpConstructorDollar9 DontDelete|ReadOnly
90@end
91*/
92
93RegExpConstructor::RegExpConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, RegExpPrototype* regExpPrototype)
94 : InternalFunction(&exec->globalData(), structure, Identifier(exec, "RegExp"))
95 , d(new RegExpConstructorPrivate)
96{
97 // ECMA 15.10.5.1 RegExp.prototype
98 putDirectWithoutTransition(propertyName: exec->propertyNames().prototype, value: regExpPrototype, attributes: DontEnum | DontDelete | ReadOnly);
99
100 // no. of arguments for constructor
101 putDirectWithoutTransition(propertyName: exec->propertyNames().length, value: jsNumber(exec, i: 2), attributes: ReadOnly | DontDelete | DontEnum);
102}
103
104RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data)
105 : JSArray(exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1)
106{
107 RegExpConstructorPrivate* d = new RegExpConstructorPrivate;
108 d->input = data->lastInput;
109 d->lastInput = data->lastInput;
110 d->lastNumSubPatterns = data->lastNumSubPatterns;
111 unsigned offsetVectorSize = (data->lastNumSubPatterns + 1) * 2; // only copying the result part of the vector
112 d->lastOvector().resize(size: offsetVectorSize);
113 memcpy(dest: d->lastOvector().data(), src: data->lastOvector().data(), n: offsetVectorSize * sizeof(int));
114 // d->multiline is not needed, and remains uninitialized
115
116 setLazyCreationData(d);
117}
118
119RegExpMatchesArray::~RegExpMatchesArray()
120{
121 delete static_cast<RegExpConstructorPrivate*>(lazyCreationData());
122}
123
124void RegExpMatchesArray::fillArrayInstance(ExecState* exec)
125{
126 RegExpConstructorPrivate* d = static_cast<RegExpConstructorPrivate*>(lazyCreationData());
127 ASSERT(d);
128
129 unsigned lastNumSubpatterns = d->lastNumSubPatterns;
130
131 for (unsigned i = 0; i <= lastNumSubpatterns; ++i) {
132 int start = d->lastOvector()[2 * i];
133 if (start >= 0)
134 JSArray::put(exec, propertyName: i, jsSubstring(exec, s: d->lastInput, offset: start, length: d->lastOvector()[2 * i + 1] - start));
135 else
136 JSArray::put(exec, propertyName: i, jsUndefined());
137 }
138
139 PutPropertySlot slot;
140 JSArray::put(exec, propertyName: exec->propertyNames().index, jsNumber(exec, i: d->lastOvector()[0]), slot);
141 JSArray::put(exec, propertyName: exec->propertyNames().input, jsString(exec, s: d->input), slot);
142
143 delete d;
144 setLazyCreationData(0);
145}
146
147JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const
148{
149 return new (exec) RegExpMatchesArray(exec, d.get());
150}
151
152JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) const
153{
154 if (!d->lastOvector().isEmpty() && i <= d->lastNumSubPatterns) {
155 int start = d->lastOvector()[2 * i];
156 if (start >= 0)
157 return jsSubstring(exec, s: d->lastInput, offset: start, length: d->lastOvector()[2 * i + 1] - start);
158 }
159 return jsEmptyString(exec);
160}
161
162JSValue RegExpConstructor::getLastParen(ExecState* exec) const
163{
164 unsigned i = d->lastNumSubPatterns;
165 if (i > 0) {
166 ASSERT(!d->lastOvector().isEmpty());
167 int start = d->lastOvector()[2 * i];
168 if (start >= 0)
169 return jsSubstring(exec, s: d->lastInput, offset: start, length: d->lastOvector()[2 * i + 1] - start);
170 }
171 return jsEmptyString(exec);
172}
173
174JSValue RegExpConstructor::getLeftContext(ExecState* exec) const
175{
176 if (!d->lastOvector().isEmpty())
177 return jsSubstring(exec, s: d->lastInput, offset: 0, length: d->lastOvector()[0]);
178 return jsEmptyString(exec);
179}
180
181JSValue RegExpConstructor::getRightContext(ExecState* exec) const
182{
183 if (!d->lastOvector().isEmpty())
184 return jsSubstring(exec, s: d->lastInput, offset: d->lastOvector()[1], length: d->lastInput.size() - d->lastOvector()[1]);
185 return jsEmptyString(exec);
186}
187
188bool RegExpConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
189{
190 return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, table: ExecState::regExpConstructorTable(callFrame: exec), thisObj: this, propertyName, slot);
191}
192
193bool RegExpConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
194{
195 return getStaticValueDescriptor<RegExpConstructor, InternalFunction>(exec, table: ExecState::regExpConstructorTable(callFrame: exec), thisObj: this, propertyName, descriptor);
196}
197
198JSValue regExpConstructorDollar1(ExecState* exec, const Identifier&, const PropertySlot& slot)
199{
200 return asRegExpConstructor(value: slot.slotBase())->getBackref(exec, i: 1);
201}
202
203JSValue regExpConstructorDollar2(ExecState* exec, const Identifier&, const PropertySlot& slot)
204{
205 return asRegExpConstructor(value: slot.slotBase())->getBackref(exec, i: 2);
206}
207
208JSValue regExpConstructorDollar3(ExecState* exec, const Identifier&, const PropertySlot& slot)
209{
210 return asRegExpConstructor(value: slot.slotBase())->getBackref(exec, i: 3);
211}
212
213JSValue regExpConstructorDollar4(ExecState* exec, const Identifier&, const PropertySlot& slot)
214{
215 return asRegExpConstructor(value: slot.slotBase())->getBackref(exec, i: 4);
216}
217
218JSValue regExpConstructorDollar5(ExecState* exec, const Identifier&, const PropertySlot& slot)
219{
220 return asRegExpConstructor(value: slot.slotBase())->getBackref(exec, i: 5);
221}
222
223JSValue regExpConstructorDollar6(ExecState* exec, const Identifier&, const PropertySlot& slot)
224{
225 return asRegExpConstructor(value: slot.slotBase())->getBackref(exec, i: 6);
226}
227
228JSValue regExpConstructorDollar7(ExecState* exec, const Identifier&, const PropertySlot& slot)
229{
230 return asRegExpConstructor(value: slot.slotBase())->getBackref(exec, i: 7);
231}
232
233JSValue regExpConstructorDollar8(ExecState* exec, const Identifier&, const PropertySlot& slot)
234{
235 return asRegExpConstructor(value: slot.slotBase())->getBackref(exec, i: 8);
236}
237
238JSValue regExpConstructorDollar9(ExecState* exec, const Identifier&, const PropertySlot& slot)
239{
240 return asRegExpConstructor(value: slot.slotBase())->getBackref(exec, i: 9);
241}
242
243JSValue regExpConstructorInput(ExecState* exec, const Identifier&, const PropertySlot& slot)
244{
245 return jsString(exec, s: asRegExpConstructor(value: slot.slotBase())->input());
246}
247
248JSValue regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot& slot)
249{
250 return jsBoolean(b: asRegExpConstructor(value: slot.slotBase())->multiline());
251}
252
253JSValue regExpConstructorLastMatch(ExecState* exec, const Identifier&, const PropertySlot& slot)
254{
255 return asRegExpConstructor(value: slot.slotBase())->getBackref(exec, i: 0);
256}
257
258JSValue regExpConstructorLastParen(ExecState* exec, const Identifier&, const PropertySlot& slot)
259{
260 return asRegExpConstructor(value: slot.slotBase())->getLastParen(exec);
261}
262
263JSValue regExpConstructorLeftContext(ExecState* exec, const Identifier&, const PropertySlot& slot)
264{
265 return asRegExpConstructor(value: slot.slotBase())->getLeftContext(exec);
266}
267
268JSValue regExpConstructorRightContext(ExecState* exec, const Identifier&, const PropertySlot& slot)
269{
270 return asRegExpConstructor(value: slot.slotBase())->getRightContext(exec);
271}
272
273void RegExpConstructor::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
274{
275 lookupPut<RegExpConstructor, InternalFunction>(exec, propertyName, value, table: ExecState::regExpConstructorTable(callFrame: exec), thisObj: this, slot);
276}
277
278void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValue value)
279{
280 asRegExpConstructor(value: baseObject)->setInput(value.toString(exec));
281}
282
283void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValue value)
284{
285 asRegExpConstructor(value: baseObject)->setMultiline(value.toBoolean(exec));
286}
287
288// ECMA 15.10.4
289JSObject* constructRegExp(ExecState* exec, const ArgList& args)
290{
291 JSValue arg0 = args.at(idx: 0);
292 JSValue arg1 = args.at(idx: 1);
293
294 if (arg0.inherits(classInfo: &RegExpObject::info)) {
295 if (!arg1.isUndefined())
296 return throwError(exec, TypeError, message: "Cannot supply flags when constructing one RegExp from another.");
297 return asObject(value: arg0);
298 }
299
300 UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec);
301 UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec);
302
303 RefPtr<RegExp> regExp = RegExp::create(globalData: &exec->globalData(), pattern, flags);
304 if (!regExp->isValid())
305 return throwError(exec, SyntaxError, message: makeString(string1: "Invalid regular expression: ", string2: regExp->errorMessage()));
306 return new (exec) RegExpObject(exec->lexicalGlobalObject()->regExpStructure(), regExp.release());
307}
308
309static JSObject* constructWithRegExpConstructor(ExecState* exec, JSObject*, const ArgList& args)
310{
311 return constructRegExp(exec, args);
312}
313
314ConstructType RegExpConstructor::getConstructData(ConstructData& constructData)
315{
316 constructData.native.function = constructWithRegExpConstructor;
317 return ConstructTypeHost;
318}
319
320// ECMA 15.10.3
321static JSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
322{
323 return constructRegExp(exec, args);
324}
325
326CallType RegExpConstructor::getCallData(CallData& callData)
327{
328 callData.native.function = callRegExpConstructor;
329 return CallTypeHost;
330}
331
332void RegExpConstructor::setInput(const UString& input)
333{
334 d->input = input;
335}
336
337const UString& RegExpConstructor::input() const
338{
339 // Can detect a distinct initial state that is invisible to JavaScript, by checking for null
340 // state (since jsString turns null strings to empty strings).
341 return d->input;
342}
343
344void RegExpConstructor::setMultiline(bool multiline)
345{
346 d->multiline = multiline;
347}
348
349bool RegExpConstructor::multiline() const
350{
351 return d->multiline;
352}
353
354} // namespace JSC
355

source code of qtscript/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.cpp