]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/RegExpConstructor.cpp
JavaScriptCore-521.tar.gz
[apple/javascriptcore.git] / runtime / RegExpConstructor.cpp
CommitLineData
9dae56ea
A
1/*
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21#include "config.h"
22#include "RegExpConstructor.h"
23
24#include "ArrayPrototype.h"
25#include "JSArray.h"
26#include "JSFunction.h"
27#include "JSString.h"
28#include "ObjectPrototype.h"
29#include "RegExpMatchesArray.h"
30#include "RegExpObject.h"
31#include "RegExpPrototype.h"
32#include "RegExp.h"
33
34namespace JSC {
35
36static JSValuePtr regExpConstructorInput(ExecState*, const Identifier&, const PropertySlot&);
37static JSValuePtr regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot&);
38static JSValuePtr regExpConstructorLastMatch(ExecState*, const Identifier&, const PropertySlot&);
39static JSValuePtr regExpConstructorLastParen(ExecState*, const Identifier&, const PropertySlot&);
40static JSValuePtr regExpConstructorLeftContext(ExecState*, const Identifier&, const PropertySlot&);
41static JSValuePtr regExpConstructorRightContext(ExecState*, const Identifier&, const PropertySlot&);
42static JSValuePtr regExpConstructorDollar1(ExecState*, const Identifier&, const PropertySlot&);
43static JSValuePtr regExpConstructorDollar2(ExecState*, const Identifier&, const PropertySlot&);
44static JSValuePtr regExpConstructorDollar3(ExecState*, const Identifier&, const PropertySlot&);
45static JSValuePtr regExpConstructorDollar4(ExecState*, const Identifier&, const PropertySlot&);
46static JSValuePtr regExpConstructorDollar5(ExecState*, const Identifier&, const PropertySlot&);
47static JSValuePtr regExpConstructorDollar6(ExecState*, const Identifier&, const PropertySlot&);
48static JSValuePtr regExpConstructorDollar7(ExecState*, const Identifier&, const PropertySlot&);
49static JSValuePtr regExpConstructorDollar8(ExecState*, const Identifier&, const PropertySlot&);
50static JSValuePtr regExpConstructorDollar9(ExecState*, const Identifier&, const PropertySlot&);
51
52static void setRegExpConstructorInput(ExecState*, JSObject*, JSValuePtr);
53static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValuePtr);
54
55} // namespace JSC
56
57#include "RegExpConstructor.lut.h"
58
59namespace JSC {
60
61ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor);
62
63const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, 0, ExecState::regExpConstructorTable };
64
65/* Source for RegExpConstructor.lut.h
66@begin regExpConstructorTable
67 input regExpConstructorInput None
68 $_ regExpConstructorInput DontEnum
69 multiline regExpConstructorMultiline None
70 $* regExpConstructorMultiline DontEnum
71 lastMatch regExpConstructorLastMatch DontDelete|ReadOnly
72 $& regExpConstructorLastMatch DontDelete|ReadOnly|DontEnum
73 lastParen regExpConstructorLastParen DontDelete|ReadOnly
74 $+ regExpConstructorLastParen DontDelete|ReadOnly|DontEnum
75 leftContext regExpConstructorLeftContext DontDelete|ReadOnly
76 $` regExpConstructorLeftContext DontDelete|ReadOnly|DontEnum
77 rightContext regExpConstructorRightContext DontDelete|ReadOnly
78 $' regExpConstructorRightContext DontDelete|ReadOnly|DontEnum
79 $1 regExpConstructorDollar1 DontDelete|ReadOnly
80 $2 regExpConstructorDollar2 DontDelete|ReadOnly
81 $3 regExpConstructorDollar3 DontDelete|ReadOnly
82 $4 regExpConstructorDollar4 DontDelete|ReadOnly
83 $5 regExpConstructorDollar5 DontDelete|ReadOnly
84 $6 regExpConstructorDollar6 DontDelete|ReadOnly
85 $7 regExpConstructorDollar7 DontDelete|ReadOnly
86 $8 regExpConstructorDollar8 DontDelete|ReadOnly
87 $9 regExpConstructorDollar9 DontDelete|ReadOnly
88@end
89*/
90
91struct RegExpConstructorPrivate {
92 // Global search cache / settings
93 RegExpConstructorPrivate()
94 : lastNumSubPatterns(0)
95 , multiline(false)
96 {
97 }
98
99 UString input;
100 UString lastInput;
101 OwnArrayPtr<int> lastOvector;
102 unsigned lastNumSubPatterns : 31;
103 bool multiline : 1;
104};
105
106RegExpConstructor::RegExpConstructor(ExecState* exec, PassRefPtr<Structure> structure, RegExpPrototype* regExpPrototype)
107 : InternalFunction(&exec->globalData(), structure, Identifier(exec, "RegExp"))
108 , d(new RegExpConstructorPrivate)
109{
110 // ECMA 15.10.5.1 RegExp.prototype
111 putDirectWithoutTransition(exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly);
112
113 // no. of arguments for constructor
114 putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly | DontDelete | DontEnum);
115}
116
117/*
118 To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular
119 expression matching through the performMatch function. We use cached results to calculate,
120 e.g., RegExp.lastMatch and RegExp.leftParen.
121*/
122void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector)
123{
124 OwnArrayPtr<int> tmpOvector;
125 position = r->match(s, startOffset, &tmpOvector);
126
127 if (ovector)
128 *ovector = tmpOvector.get();
129
130 if (position != -1) {
131 ASSERT(tmpOvector);
132
133 length = tmpOvector[1] - tmpOvector[0];
134
135 d->input = s;
136 d->lastInput = s;
137 d->lastOvector.set(tmpOvector.release());
138 d->lastNumSubPatterns = r->numSubpatterns();
139 }
140}
141
142RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data)
143 : JSArray(exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1)
144{
145 RegExpConstructorPrivate* d = new RegExpConstructorPrivate;
146 d->input = data->lastInput;
147 d->lastInput = data->lastInput;
148 d->lastNumSubPatterns = data->lastNumSubPatterns;
149 unsigned offsetVectorSize = (data->lastNumSubPatterns + 1) * 2; // only copying the result part of the vector
150 d->lastOvector.set(new int[offsetVectorSize]);
151 memcpy(d->lastOvector.get(), data->lastOvector.get(), offsetVectorSize * sizeof(int));
152 // d->multiline is not needed, and remains uninitialized
153
154 setLazyCreationData(d);
155}
156
157RegExpMatchesArray::~RegExpMatchesArray()
158{
159 delete static_cast<RegExpConstructorPrivate*>(lazyCreationData());
160}
161
162void RegExpMatchesArray::fillArrayInstance(ExecState* exec)
163{
164 RegExpConstructorPrivate* d = static_cast<RegExpConstructorPrivate*>(lazyCreationData());
165 ASSERT(d);
166
167 unsigned lastNumSubpatterns = d->lastNumSubPatterns;
168
169 for (unsigned i = 0; i <= lastNumSubpatterns; ++i) {
170 int start = d->lastOvector[2 * i];
171 if (start >= 0)
172 JSArray::put(exec, i, jsSubstring(exec, d->lastInput, start, d->lastOvector[2 * i + 1] - start));
173 }
174
175 PutPropertySlot slot;
176 JSArray::put(exec, exec->propertyNames().index, jsNumber(exec, d->lastOvector[0]), slot);
177 JSArray::put(exec, exec->propertyNames().input, jsString(exec, d->input), slot);
178
179 delete d;
180 setLazyCreationData(0);
181}
182
183JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const
184{
185 return new (exec) RegExpMatchesArray(exec, d.get());
186}
187
188JSValuePtr RegExpConstructor::getBackref(ExecState* exec, unsigned i) const
189{
190 if (d->lastOvector && i <= d->lastNumSubPatterns) {
191 int start = d->lastOvector[2 * i];
192 if (start >= 0)
193 return jsSubstring(exec, d->lastInput, start, d->lastOvector[2 * i + 1] - start);
194 }
195 return jsEmptyString(exec);
196}
197
198JSValuePtr RegExpConstructor::getLastParen(ExecState* exec) const
199{
200 unsigned i = d->lastNumSubPatterns;
201 if (i > 0) {
202 ASSERT(d->lastOvector);
203 int start = d->lastOvector[2 * i];
204 if (start >= 0)
205 return jsSubstring(exec, d->lastInput, start, d->lastOvector[2 * i + 1] - start);
206 }
207 return jsEmptyString(exec);
208}
209
210JSValuePtr RegExpConstructor::getLeftContext(ExecState* exec) const
211{
212 if (d->lastOvector)
213 return jsSubstring(exec, d->lastInput, 0, d->lastOvector[0]);
214 return jsEmptyString(exec);
215}
216
217JSValuePtr RegExpConstructor::getRightContext(ExecState* exec) const
218{
219 if (d->lastOvector)
220 return jsSubstring(exec, d->lastInput, d->lastOvector[1], d->lastInput.size() - d->lastOvector[1]);
221 return jsEmptyString(exec);
222}
223
224bool RegExpConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
225{
226 return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, slot);
227}
228
229JSValuePtr regExpConstructorDollar1(ExecState* exec, const Identifier&, const PropertySlot& slot)
230{
231 return asRegExpConstructor(slot.slotBase())->getBackref(exec, 1);
232}
233
234JSValuePtr regExpConstructorDollar2(ExecState* exec, const Identifier&, const PropertySlot& slot)
235{
236 return asRegExpConstructor(slot.slotBase())->getBackref(exec, 2);
237}
238
239JSValuePtr regExpConstructorDollar3(ExecState* exec, const Identifier&, const PropertySlot& slot)
240{
241 return asRegExpConstructor(slot.slotBase())->getBackref(exec, 3);
242}
243
244JSValuePtr regExpConstructorDollar4(ExecState* exec, const Identifier&, const PropertySlot& slot)
245{
246 return asRegExpConstructor(slot.slotBase())->getBackref(exec, 4);
247}
248
249JSValuePtr regExpConstructorDollar5(ExecState* exec, const Identifier&, const PropertySlot& slot)
250{
251 return asRegExpConstructor(slot.slotBase())->getBackref(exec, 5);
252}
253
254JSValuePtr regExpConstructorDollar6(ExecState* exec, const Identifier&, const PropertySlot& slot)
255{
256 return asRegExpConstructor(slot.slotBase())->getBackref(exec, 6);
257}
258
259JSValuePtr regExpConstructorDollar7(ExecState* exec, const Identifier&, const PropertySlot& slot)
260{
261 return asRegExpConstructor(slot.slotBase())->getBackref(exec, 7);
262}
263
264JSValuePtr regExpConstructorDollar8(ExecState* exec, const Identifier&, const PropertySlot& slot)
265{
266 return asRegExpConstructor(slot.slotBase())->getBackref(exec, 8);
267}
268
269JSValuePtr regExpConstructorDollar9(ExecState* exec, const Identifier&, const PropertySlot& slot)
270{
271 return asRegExpConstructor(slot.slotBase())->getBackref(exec, 9);
272}
273
274JSValuePtr regExpConstructorInput(ExecState* exec, const Identifier&, const PropertySlot& slot)
275{
276 return jsString(exec, asRegExpConstructor(slot.slotBase())->input());
277}
278
279JSValuePtr regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot& slot)
280{
281 return jsBoolean(asRegExpConstructor(slot.slotBase())->multiline());
282}
283
284JSValuePtr regExpConstructorLastMatch(ExecState* exec, const Identifier&, const PropertySlot& slot)
285{
286 return asRegExpConstructor(slot.slotBase())->getBackref(exec, 0);
287}
288
289JSValuePtr regExpConstructorLastParen(ExecState* exec, const Identifier&, const PropertySlot& slot)
290{
291 return asRegExpConstructor(slot.slotBase())->getLastParen(exec);
292}
293
294JSValuePtr regExpConstructorLeftContext(ExecState* exec, const Identifier&, const PropertySlot& slot)
295{
296 return asRegExpConstructor(slot.slotBase())->getLeftContext(exec);
297}
298
299JSValuePtr regExpConstructorRightContext(ExecState* exec, const Identifier&, const PropertySlot& slot)
300{
301 return asRegExpConstructor(slot.slotBase())->getRightContext(exec);
302}
303
304void RegExpConstructor::put(ExecState* exec, const Identifier& propertyName, JSValuePtr value, PutPropertySlot& slot)
305{
306 lookupPut<RegExpConstructor, InternalFunction>(exec, propertyName, value, ExecState::regExpConstructorTable(exec), this, slot);
307}
308
309void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValuePtr value)
310{
311 asRegExpConstructor(baseObject)->setInput(value.toString(exec));
312}
313
314void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValuePtr value)
315{
316 asRegExpConstructor(baseObject)->setMultiline(value.toBoolean(exec));
317}
318
319// ECMA 15.10.4
320JSObject* constructRegExp(ExecState* exec, const ArgList& args)
321{
322 JSValuePtr arg0 = args.at(exec, 0);
323 JSValuePtr arg1 = args.at(exec, 1);
324
325 if (arg0.isObject(&RegExpObject::info)) {
326 if (!arg1.isUndefined())
327 return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another.");
328 return asObject(arg0);
329 }
330
331 UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec);
332 UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec);
333
334 RefPtr<RegExp> regExp = RegExp::create(&exec->globalData(), pattern, flags);
335 if (!regExp->isValid())
336 return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage()));
337 return new (exec) RegExpObject(exec->lexicalGlobalObject()->regExpStructure(), regExp.release());
338}
339
340static JSObject* constructWithRegExpConstructor(ExecState* exec, JSObject*, const ArgList& args)
341{
342 return constructRegExp(exec, args);
343}
344
345ConstructType RegExpConstructor::getConstructData(ConstructData& constructData)
346{
347 constructData.native.function = constructWithRegExpConstructor;
348 return ConstructTypeHost;
349}
350
351// ECMA 15.10.3
352static JSValuePtr callRegExpConstructor(ExecState* exec, JSObject*, JSValuePtr, const ArgList& args)
353{
354 return constructRegExp(exec, args);
355}
356
357CallType RegExpConstructor::getCallData(CallData& callData)
358{
359 callData.native.function = callRegExpConstructor;
360 return CallTypeHost;
361}
362
363void RegExpConstructor::setInput(const UString& input)
364{
365 d->input = input;
366}
367
368const UString& RegExpConstructor::input() const
369{
370 // Can detect a distinct initial state that is invisible to JavaScript, by checking for null
371 // state (since jsString turns null strings to empty strings).
372 return d->input;
373}
374
375void RegExpConstructor::setMultiline(bool multiline)
376{
377 d->multiline = multiline;
378}
379
380bool RegExpConstructor::multiline() const
381{
382 return d->multiline;
383}
384
385} // namespace JSC