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 "ExceptionHelpers.h"
29 #include "JSFunction.h"
32 #include "ObjectPrototype.h"
33 #include "RegExpMatchesArray.h"
34 #include "RegExpObject.h"
35 #include "RegExpPrototype.h"
37 #include "RegExpCache.h"
38 #include "UStringConcatenate.h"
39 #include <wtf/PassOwnPtr.h>
41 #include <wtf/PassOwnPtr.h>
45 static JSValue
regExpConstructorInput(ExecState
*, JSValue
, const Identifier
&);
46 static JSValue
regExpConstructorMultiline(ExecState
*, JSValue
, const Identifier
&);
47 static JSValue
regExpConstructorLastMatch(ExecState
*, JSValue
, const Identifier
&);
48 static JSValue
regExpConstructorLastParen(ExecState
*, JSValue
, const Identifier
&);
49 static JSValue
regExpConstructorLeftContext(ExecState
*, JSValue
, const Identifier
&);
50 static JSValue
regExpConstructorRightContext(ExecState
*, JSValue
, const Identifier
&);
51 static JSValue
regExpConstructorDollar1(ExecState
*, JSValue
, const Identifier
&);
52 static JSValue
regExpConstructorDollar2(ExecState
*, JSValue
, const Identifier
&);
53 static JSValue
regExpConstructorDollar3(ExecState
*, JSValue
, const Identifier
&);
54 static JSValue
regExpConstructorDollar4(ExecState
*, JSValue
, const Identifier
&);
55 static JSValue
regExpConstructorDollar5(ExecState
*, JSValue
, const Identifier
&);
56 static JSValue
regExpConstructorDollar6(ExecState
*, JSValue
, const Identifier
&);
57 static JSValue
regExpConstructorDollar7(ExecState
*, JSValue
, const Identifier
&);
58 static JSValue
regExpConstructorDollar8(ExecState
*, JSValue
, const Identifier
&);
59 static JSValue
regExpConstructorDollar9(ExecState
*, JSValue
, const Identifier
&);
61 static void setRegExpConstructorInput(ExecState
*, JSObject
*, JSValue
);
62 static void setRegExpConstructorMultiline(ExecState
*, JSObject
*, JSValue
);
66 #include "RegExpConstructor.lut.h"
70 ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor
);
72 const ClassInfo
RegExpConstructor::s_info
= { "Function", &InternalFunction::s_info
, 0, ExecState::regExpConstructorTable
};
74 /* Source for RegExpConstructor.lut.h
75 @begin regExpConstructorTable
76 input regExpConstructorInput None
77 $_ regExpConstructorInput DontEnum
78 multiline regExpConstructorMultiline None
79 $* regExpConstructorMultiline DontEnum
80 lastMatch regExpConstructorLastMatch DontDelete|ReadOnly
81 $& regExpConstructorLastMatch DontDelete|ReadOnly|DontEnum
82 lastParen regExpConstructorLastParen DontDelete|ReadOnly
83 $+ regExpConstructorLastParen DontDelete|ReadOnly|DontEnum
84 leftContext regExpConstructorLeftContext DontDelete|ReadOnly
85 $` regExpConstructorLeftContext DontDelete|ReadOnly|DontEnum
86 rightContext regExpConstructorRightContext DontDelete|ReadOnly
87 $' regExpConstructorRightContext DontDelete|ReadOnly|DontEnum
88 $1 regExpConstructorDollar1 DontDelete|ReadOnly
89 $2 regExpConstructorDollar2 DontDelete|ReadOnly
90 $3 regExpConstructorDollar3 DontDelete|ReadOnly
91 $4 regExpConstructorDollar4 DontDelete|ReadOnly
92 $5 regExpConstructorDollar5 DontDelete|ReadOnly
93 $6 regExpConstructorDollar6 DontDelete|ReadOnly
94 $7 regExpConstructorDollar7 DontDelete|ReadOnly
95 $8 regExpConstructorDollar8 DontDelete|ReadOnly
96 $9 regExpConstructorDollar9 DontDelete|ReadOnly
100 RegExpConstructor::RegExpConstructor(ExecState
* exec
, JSGlobalObject
* globalObject
, Structure
* structure
, RegExpPrototype
* regExpPrototype
)
101 : InternalFunction(&exec
->globalData(), globalObject
, structure
, Identifier(exec
, "RegExp"))
102 , d(adoptPtr(new RegExpConstructorPrivate
))
104 ASSERT(inherits(&s_info
));
106 // ECMA 15.10.5.1 RegExp.prototype
107 putDirectWithoutTransition(exec
->globalData(), exec
->propertyNames().prototype
, regExpPrototype
, DontEnum
| DontDelete
| ReadOnly
);
109 // no. of arguments for constructor
110 putDirectWithoutTransition(exec
->globalData(), exec
->propertyNames().length
, jsNumber(2), ReadOnly
| DontDelete
| DontEnum
);
113 RegExpMatchesArray::RegExpMatchesArray(ExecState
* exec
, RegExpConstructorPrivate
* data
)
114 : JSArray(exec
->globalData(), exec
->lexicalGlobalObject()->regExpMatchesArrayStructure(), data
->lastNumSubPatterns
+ 1, CreateInitialized
)
116 RegExpConstructorPrivate
* d
= new RegExpConstructorPrivate
;
117 d
->input
= data
->lastInput
;
118 d
->lastInput
= data
->lastInput
;
119 d
->lastNumSubPatterns
= data
->lastNumSubPatterns
;
120 unsigned offsetVectorSize
= (data
->lastNumSubPatterns
+ 1) * 2; // only copying the result part of the vector
121 d
->lastOvector().resize(offsetVectorSize
);
122 memcpy(d
->lastOvector().data(), data
->lastOvector().data(), offsetVectorSize
* sizeof(int));
123 // d->multiline is not needed, and remains uninitialized
128 RegExpMatchesArray::~RegExpMatchesArray()
130 delete static_cast<RegExpConstructorPrivate
*>(subclassData());
133 void RegExpMatchesArray::fillArrayInstance(ExecState
* exec
)
135 RegExpConstructorPrivate
* d
= static_cast<RegExpConstructorPrivate
*>(subclassData());
138 unsigned lastNumSubpatterns
= d
->lastNumSubPatterns
;
140 for (unsigned i
= 0; i
<= lastNumSubpatterns
; ++i
) {
141 int start
= d
->lastOvector()[2 * i
];
143 JSArray::put(exec
, i
, jsSubstring(exec
, d
->lastInput
, start
, d
->lastOvector()[2 * i
+ 1] - start
));
145 JSArray::put(exec
, i
, jsUndefined());
148 PutPropertySlot slot
;
149 JSArray::put(exec
, exec
->propertyNames().index
, jsNumber(d
->lastOvector()[0]), slot
);
150 JSArray::put(exec
, exec
->propertyNames().input
, jsString(exec
, d
->input
), slot
);
156 JSObject
* RegExpConstructor::arrayOfMatches(ExecState
* exec
) const
158 return new (exec
) RegExpMatchesArray(exec
, d
.get());
161 JSValue
RegExpConstructor::getBackref(ExecState
* exec
, unsigned i
) const
163 if (!d
->lastOvector().isEmpty() && i
<= d
->lastNumSubPatterns
) {
164 int start
= d
->lastOvector()[2 * i
];
166 return jsSubstring(exec
, d
->lastInput
, start
, d
->lastOvector()[2 * i
+ 1] - start
);
168 return jsEmptyString(exec
);
171 JSValue
RegExpConstructor::getLastParen(ExecState
* exec
) const
173 unsigned i
= d
->lastNumSubPatterns
;
175 ASSERT(!d
->lastOvector().isEmpty());
176 int start
= d
->lastOvector()[2 * i
];
178 return jsSubstring(exec
, d
->lastInput
, start
, d
->lastOvector()[2 * i
+ 1] - start
);
180 return jsEmptyString(exec
);
183 JSValue
RegExpConstructor::getLeftContext(ExecState
* exec
) const
185 if (!d
->lastOvector().isEmpty())
186 return jsSubstring(exec
, d
->lastInput
, 0, d
->lastOvector()[0]);
187 return jsEmptyString(exec
);
190 JSValue
RegExpConstructor::getRightContext(ExecState
* exec
) const
192 if (!d
->lastOvector().isEmpty())
193 return jsSubstring(exec
, d
->lastInput
, d
->lastOvector()[1], d
->lastInput
.length() - d
->lastOvector()[1]);
194 return jsEmptyString(exec
);
197 bool RegExpConstructor::getOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
199 return getStaticValueSlot
<RegExpConstructor
, InternalFunction
>(exec
, ExecState::regExpConstructorTable(exec
), this, propertyName
, slot
);
202 bool RegExpConstructor::getOwnPropertyDescriptor(ExecState
* exec
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
)
204 return getStaticValueDescriptor
<RegExpConstructor
, InternalFunction
>(exec
, ExecState::regExpConstructorTable(exec
), this, propertyName
, descriptor
);
207 JSValue
regExpConstructorDollar1(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
209 return asRegExpConstructor(slotBase
)->getBackref(exec
, 1);
212 JSValue
regExpConstructorDollar2(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
214 return asRegExpConstructor(slotBase
)->getBackref(exec
, 2);
217 JSValue
regExpConstructorDollar3(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
219 return asRegExpConstructor(slotBase
)->getBackref(exec
, 3);
222 JSValue
regExpConstructorDollar4(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
224 return asRegExpConstructor(slotBase
)->getBackref(exec
, 4);
227 JSValue
regExpConstructorDollar5(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
229 return asRegExpConstructor(slotBase
)->getBackref(exec
, 5);
232 JSValue
regExpConstructorDollar6(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
234 return asRegExpConstructor(slotBase
)->getBackref(exec
, 6);
237 JSValue
regExpConstructorDollar7(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
239 return asRegExpConstructor(slotBase
)->getBackref(exec
, 7);
242 JSValue
regExpConstructorDollar8(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
244 return asRegExpConstructor(slotBase
)->getBackref(exec
, 8);
247 JSValue
regExpConstructorDollar9(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
249 return asRegExpConstructor(slotBase
)->getBackref(exec
, 9);
252 JSValue
regExpConstructorInput(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
254 return jsString(exec
, asRegExpConstructor(slotBase
)->input());
257 JSValue
regExpConstructorMultiline(ExecState
*, JSValue slotBase
, const Identifier
&)
259 return jsBoolean(asRegExpConstructor(slotBase
)->multiline());
262 JSValue
regExpConstructorLastMatch(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
264 return asRegExpConstructor(slotBase
)->getBackref(exec
, 0);
267 JSValue
regExpConstructorLastParen(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
269 return asRegExpConstructor(slotBase
)->getLastParen(exec
);
272 JSValue
regExpConstructorLeftContext(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
274 return asRegExpConstructor(slotBase
)->getLeftContext(exec
);
277 JSValue
regExpConstructorRightContext(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
279 return asRegExpConstructor(slotBase
)->getRightContext(exec
);
282 void RegExpConstructor::put(ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, PutPropertySlot
& slot
)
284 lookupPut
<RegExpConstructor
, InternalFunction
>(exec
, propertyName
, value
, ExecState::regExpConstructorTable(exec
), this, slot
);
287 void setRegExpConstructorInput(ExecState
* exec
, JSObject
* baseObject
, JSValue value
)
289 asRegExpConstructor(baseObject
)->setInput(value
.toString(exec
));
292 void setRegExpConstructorMultiline(ExecState
* exec
, JSObject
* baseObject
, JSValue value
)
294 asRegExpConstructor(baseObject
)->setMultiline(value
.toBoolean(exec
));
298 JSObject
* constructRegExp(ExecState
* exec
, JSGlobalObject
* globalObject
, const ArgList
& args
)
300 JSValue arg0
= args
.at(0);
301 JSValue arg1
= args
.at(1);
303 if (arg0
.inherits(&RegExpObject::s_info
)) {
304 if (!arg1
.isUndefined())
305 return throwError(exec
, createTypeError(exec
, "Cannot supply flags when constructing one RegExp from another."));
306 return asObject(arg0
);
309 UString pattern
= arg0
.isUndefined() ? UString("") : arg0
.toString(exec
);
310 if (exec
->hadException())
313 RegExpFlags flags
= NoFlags
;
314 if (!arg1
.isUndefined()) {
315 flags
= regExpFlags(arg1
.toString(exec
));
316 if (exec
->hadException())
318 if (flags
== InvalidFlags
)
319 return throwError(exec
, createSyntaxError(exec
, "Invalid flags supplied to RegExp constructor."));
322 RegExp
* regExp
= RegExp::create(&exec
->globalData(), pattern
, flags
);
323 if (!regExp
->isValid())
324 return throwError(exec
, createSyntaxError(exec
, regExp
->errorMessage()));
325 return new (exec
) RegExpObject(exec
->lexicalGlobalObject(), globalObject
->regExpStructure(), regExp
);
328 static EncodedJSValue JSC_HOST_CALL
constructWithRegExpConstructor(ExecState
* exec
)
331 return JSValue::encode(constructRegExp(exec
, asInternalFunction(exec
->callee())->globalObject(), args
));
334 ConstructType
RegExpConstructor::getConstructData(ConstructData
& constructData
)
336 constructData
.native
.function
= constructWithRegExpConstructor
;
337 return ConstructTypeHost
;
341 static EncodedJSValue JSC_HOST_CALL
callRegExpConstructor(ExecState
* exec
)
344 return JSValue::encode(constructRegExp(exec
, asInternalFunction(exec
->callee())->globalObject(), args
));
347 CallType
RegExpConstructor::getCallData(CallData
& callData
)
349 callData
.native
.function
= callRegExpConstructor
;
353 void RegExpConstructor::setInput(const UString
& input
)
358 const UString
& RegExpConstructor::input() const
360 // Can detect a distinct initial state that is invisible to JavaScript, by checking for null
361 // state (since jsString turns null strings to empty strings).
365 void RegExpConstructor::setMultiline(bool multiline
)
367 d
->multiline
= multiline
;
370 bool RegExpConstructor::multiline() const