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.
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.
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.
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
23 #include "RegExpConstructor.h"
25 #include "ArrayPrototype.h"
27 #include "JSFunction.h"
29 #include "ObjectPrototype.h"
30 #include "RegExpMatchesArray.h"
31 #include "RegExpObject.h"
32 #include "RegExpPrototype.h"
37 static JSValue
regExpConstructorInput(ExecState
*, const Identifier
&, const PropertySlot
&);
38 static JSValue
regExpConstructorMultiline(ExecState
*, const Identifier
&, const PropertySlot
&);
39 static JSValue
regExpConstructorLastMatch(ExecState
*, const Identifier
&, const PropertySlot
&);
40 static JSValue
regExpConstructorLastParen(ExecState
*, const Identifier
&, const PropertySlot
&);
41 static JSValue
regExpConstructorLeftContext(ExecState
*, const Identifier
&, const PropertySlot
&);
42 static JSValue
regExpConstructorRightContext(ExecState
*, const Identifier
&, const PropertySlot
&);
43 static JSValue
regExpConstructorDollar1(ExecState
*, const Identifier
&, const PropertySlot
&);
44 static JSValue
regExpConstructorDollar2(ExecState
*, const Identifier
&, const PropertySlot
&);
45 static JSValue
regExpConstructorDollar3(ExecState
*, const Identifier
&, const PropertySlot
&);
46 static JSValue
regExpConstructorDollar4(ExecState
*, const Identifier
&, const PropertySlot
&);
47 static JSValue
regExpConstructorDollar5(ExecState
*, const Identifier
&, const PropertySlot
&);
48 static JSValue
regExpConstructorDollar6(ExecState
*, const Identifier
&, const PropertySlot
&);
49 static JSValue
regExpConstructorDollar7(ExecState
*, const Identifier
&, const PropertySlot
&);
50 static JSValue
regExpConstructorDollar8(ExecState
*, const Identifier
&, const PropertySlot
&);
51 static JSValue
regExpConstructorDollar9(ExecState
*, const Identifier
&, const PropertySlot
&);
53 static void setRegExpConstructorInput(ExecState
*, JSObject
*, JSValue
);
54 static void setRegExpConstructorMultiline(ExecState
*, JSObject
*, JSValue
);
58 #include "RegExpConstructor.lut.h"
62 ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor
);
64 const ClassInfo
RegExpConstructor::info
= { "Function", &InternalFunction::info
, 0, ExecState::regExpConstructorTable
};
66 /* Source for RegExpConstructor.lut.h
67 @begin regExpConstructorTable
68 input regExpConstructorInput None
69 $_ regExpConstructorInput DontEnum
70 multiline regExpConstructorMultiline None
71 $* regExpConstructorMultiline DontEnum
72 lastMatch regExpConstructorLastMatch DontDelete|ReadOnly
73 $& regExpConstructorLastMatch DontDelete|ReadOnly|DontEnum
74 lastParen regExpConstructorLastParen DontDelete|ReadOnly
75 $+ regExpConstructorLastParen DontDelete|ReadOnly|DontEnum
76 leftContext regExpConstructorLeftContext DontDelete|ReadOnly
77 $` regExpConstructorLeftContext DontDelete|ReadOnly|DontEnum
78 rightContext regExpConstructorRightContext DontDelete|ReadOnly
79 $' regExpConstructorRightContext DontDelete|ReadOnly|DontEnum
80 $1 regExpConstructorDollar1 DontDelete|ReadOnly
81 $2 regExpConstructorDollar2 DontDelete|ReadOnly
82 $3 regExpConstructorDollar3 DontDelete|ReadOnly
83 $4 regExpConstructorDollar4 DontDelete|ReadOnly
84 $5 regExpConstructorDollar5 DontDelete|ReadOnly
85 $6 regExpConstructorDollar6 DontDelete|ReadOnly
86 $7 regExpConstructorDollar7 DontDelete|ReadOnly
87 $8 regExpConstructorDollar8 DontDelete|ReadOnly
88 $9 regExpConstructorDollar9 DontDelete|ReadOnly
92 struct RegExpConstructorPrivate
{
93 // Global search cache / settings
94 RegExpConstructorPrivate()
95 : lastNumSubPatterns(0)
101 const Vector
<int, 32>& lastOvector() const { return ovector
[lastOvectorIndex
]; }
102 Vector
<int, 32>& lastOvector() { return ovector
[lastOvectorIndex
]; }
103 Vector
<int, 32>& tempOvector() { return ovector
[lastOvectorIndex
? 0 : 1]; }
104 void changeLastOvector() { lastOvectorIndex
= lastOvectorIndex
? 0 : 1; }
108 Vector
<int, 32> ovector
[2];
109 unsigned lastNumSubPatterns
: 30;
111 unsigned lastOvectorIndex
: 1;
114 RegExpConstructor::RegExpConstructor(ExecState
* exec
, PassRefPtr
<Structure
> structure
, RegExpPrototype
* regExpPrototype
)
115 : InternalFunction(&exec
->globalData(), structure
, Identifier(exec
, "RegExp"))
116 , d(new RegExpConstructorPrivate
)
118 // ECMA 15.10.5.1 RegExp.prototype
119 putDirectWithoutTransition(exec
->propertyNames().prototype
, regExpPrototype
, DontEnum
| DontDelete
| ReadOnly
);
121 // no. of arguments for constructor
122 putDirectWithoutTransition(exec
->propertyNames().length
, jsNumber(exec
, 2), ReadOnly
| DontDelete
| DontEnum
);
126 To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular
127 expression matching through the performMatch function. We use cached results to calculate,
128 e.g., RegExp.lastMatch and RegExp.leftParen.
130 void RegExpConstructor::performMatch(RegExp
* r
, const UString
& s
, int startOffset
, int& position
, int& length
, int** ovector
)
132 position
= r
->match(s
, startOffset
, &d
->tempOvector());
135 *ovector
= d
->tempOvector().data();
137 if (position
!= -1) {
138 ASSERT(!d
->tempOvector().isEmpty());
140 length
= d
->tempOvector()[1] - d
->tempOvector()[0];
144 d
->changeLastOvector();
145 d
->lastNumSubPatterns
= r
->numSubpatterns();
149 RegExpMatchesArray::RegExpMatchesArray(ExecState
* exec
, RegExpConstructorPrivate
* data
)
150 : JSArray(exec
->lexicalGlobalObject()->regExpMatchesArrayStructure(), data
->lastNumSubPatterns
+ 1)
152 RegExpConstructorPrivate
* d
= new RegExpConstructorPrivate
;
153 d
->input
= data
->lastInput
;
154 d
->lastInput
= data
->lastInput
;
155 d
->lastNumSubPatterns
= data
->lastNumSubPatterns
;
156 unsigned offsetVectorSize
= (data
->lastNumSubPatterns
+ 1) * 2; // only copying the result part of the vector
157 d
->lastOvector().resize(offsetVectorSize
);
158 memcpy(d
->lastOvector().data(), data
->lastOvector().data(), offsetVectorSize
* sizeof(int));
159 // d->multiline is not needed, and remains uninitialized
161 setLazyCreationData(d
);
164 RegExpMatchesArray::~RegExpMatchesArray()
166 delete static_cast<RegExpConstructorPrivate
*>(lazyCreationData());
169 void RegExpMatchesArray::fillArrayInstance(ExecState
* exec
)
171 RegExpConstructorPrivate
* d
= static_cast<RegExpConstructorPrivate
*>(lazyCreationData());
174 unsigned lastNumSubpatterns
= d
->lastNumSubPatterns
;
176 for (unsigned i
= 0; i
<= lastNumSubpatterns
; ++i
) {
177 int start
= d
->lastOvector()[2 * i
];
179 JSArray::put(exec
, i
, jsSubstring(exec
, d
->lastInput
, start
, d
->lastOvector()[2 * i
+ 1] - start
));
182 PutPropertySlot slot
;
183 JSArray::put(exec
, exec
->propertyNames().index
, jsNumber(exec
, d
->lastOvector()[0]), slot
);
184 JSArray::put(exec
, exec
->propertyNames().input
, jsString(exec
, d
->input
), slot
);
187 setLazyCreationData(0);
190 JSObject
* RegExpConstructor::arrayOfMatches(ExecState
* exec
) const
192 return new (exec
) RegExpMatchesArray(exec
, d
.get());
195 JSValue
RegExpConstructor::getBackref(ExecState
* exec
, unsigned i
) const
197 if (!d
->lastOvector().isEmpty() && i
<= d
->lastNumSubPatterns
) {
198 int start
= d
->lastOvector()[2 * i
];
200 return jsSubstring(exec
, d
->lastInput
, start
, d
->lastOvector()[2 * i
+ 1] - start
);
202 return jsEmptyString(exec
);
205 JSValue
RegExpConstructor::getLastParen(ExecState
* exec
) const
207 unsigned i
= d
->lastNumSubPatterns
;
209 ASSERT(!d
->lastOvector().isEmpty());
210 int start
= d
->lastOvector()[2 * i
];
212 return jsSubstring(exec
, d
->lastInput
, start
, d
->lastOvector()[2 * i
+ 1] - start
);
214 return jsEmptyString(exec
);
217 JSValue
RegExpConstructor::getLeftContext(ExecState
* exec
) const
219 if (!d
->lastOvector().isEmpty())
220 return jsSubstring(exec
, d
->lastInput
, 0, d
->lastOvector()[0]);
221 return jsEmptyString(exec
);
224 JSValue
RegExpConstructor::getRightContext(ExecState
* exec
) const
226 if (!d
->lastOvector().isEmpty())
227 return jsSubstring(exec
, d
->lastInput
, d
->lastOvector()[1], d
->lastInput
.size() - d
->lastOvector()[1]);
228 return jsEmptyString(exec
);
231 bool RegExpConstructor::getOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
233 return getStaticValueSlot
<RegExpConstructor
, InternalFunction
>(exec
, ExecState::regExpConstructorTable(exec
), this, propertyName
, slot
);
236 JSValue
regExpConstructorDollar1(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
238 return asRegExpConstructor(slot
.slotBase())->getBackref(exec
, 1);
241 JSValue
regExpConstructorDollar2(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
243 return asRegExpConstructor(slot
.slotBase())->getBackref(exec
, 2);
246 JSValue
regExpConstructorDollar3(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
248 return asRegExpConstructor(slot
.slotBase())->getBackref(exec
, 3);
251 JSValue
regExpConstructorDollar4(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
253 return asRegExpConstructor(slot
.slotBase())->getBackref(exec
, 4);
256 JSValue
regExpConstructorDollar5(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
258 return asRegExpConstructor(slot
.slotBase())->getBackref(exec
, 5);
261 JSValue
regExpConstructorDollar6(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
263 return asRegExpConstructor(slot
.slotBase())->getBackref(exec
, 6);
266 JSValue
regExpConstructorDollar7(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
268 return asRegExpConstructor(slot
.slotBase())->getBackref(exec
, 7);
271 JSValue
regExpConstructorDollar8(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
273 return asRegExpConstructor(slot
.slotBase())->getBackref(exec
, 8);
276 JSValue
regExpConstructorDollar9(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
278 return asRegExpConstructor(slot
.slotBase())->getBackref(exec
, 9);
281 JSValue
regExpConstructorInput(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
283 return jsString(exec
, asRegExpConstructor(slot
.slotBase())->input());
286 JSValue
regExpConstructorMultiline(ExecState
*, const Identifier
&, const PropertySlot
& slot
)
288 return jsBoolean(asRegExpConstructor(slot
.slotBase())->multiline());
291 JSValue
regExpConstructorLastMatch(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
293 return asRegExpConstructor(slot
.slotBase())->getBackref(exec
, 0);
296 JSValue
regExpConstructorLastParen(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
298 return asRegExpConstructor(slot
.slotBase())->getLastParen(exec
);
301 JSValue
regExpConstructorLeftContext(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
303 return asRegExpConstructor(slot
.slotBase())->getLeftContext(exec
);
306 JSValue
regExpConstructorRightContext(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
308 return asRegExpConstructor(slot
.slotBase())->getRightContext(exec
);
311 void RegExpConstructor::put(ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, PutPropertySlot
& slot
)
313 lookupPut
<RegExpConstructor
, InternalFunction
>(exec
, propertyName
, value
, ExecState::regExpConstructorTable(exec
), this, slot
);
316 void setRegExpConstructorInput(ExecState
* exec
, JSObject
* baseObject
, JSValue value
)
318 asRegExpConstructor(baseObject
)->setInput(value
.toString(exec
));
321 void setRegExpConstructorMultiline(ExecState
* exec
, JSObject
* baseObject
, JSValue value
)
323 asRegExpConstructor(baseObject
)->setMultiline(value
.toBoolean(exec
));
327 JSObject
* constructRegExp(ExecState
* exec
, const ArgList
& args
)
329 JSValue arg0
= args
.at(0);
330 JSValue arg1
= args
.at(1);
332 if (arg0
.isObject(&RegExpObject::info
)) {
333 if (!arg1
.isUndefined())
334 return throwError(exec
, TypeError
, "Cannot supply flags when constructing one RegExp from another.");
335 return asObject(arg0
);
338 UString pattern
= arg0
.isUndefined() ? UString("") : arg0
.toString(exec
);
339 UString flags
= arg1
.isUndefined() ? UString("") : arg1
.toString(exec
);
341 RefPtr
<RegExp
> regExp
= RegExp::create(&exec
->globalData(), pattern
, flags
);
342 if (!regExp
->isValid())
343 return throwError(exec
, SyntaxError
, UString("Invalid regular expression: ").append(regExp
->errorMessage()));
344 return new (exec
) RegExpObject(exec
->lexicalGlobalObject()->regExpStructure(), regExp
.release());
347 static JSObject
* constructWithRegExpConstructor(ExecState
* exec
, JSObject
*, const ArgList
& args
)
349 return constructRegExp(exec
, args
);
352 ConstructType
RegExpConstructor::getConstructData(ConstructData
& constructData
)
354 constructData
.native
.function
= constructWithRegExpConstructor
;
355 return ConstructTypeHost
;
359 static JSValue JSC_HOST_CALL
callRegExpConstructor(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
361 return constructRegExp(exec
, args
);
364 CallType
RegExpConstructor::getCallData(CallData
& callData
)
366 callData
.native
.function
= callRegExpConstructor
;
370 void RegExpConstructor::setInput(const UString
& input
)
375 const UString
& RegExpConstructor::input() const
377 // Can detect a distinct initial state that is invisible to JavaScript, by checking for null
378 // state (since jsString turns null strings to empty strings).
382 void RegExpConstructor::setMultiline(bool multiline
)
384 d
->multiline
= multiline
;
387 bool RegExpConstructor::multiline() const