]>
Commit | Line | Data |
---|---|---|
9dae56ea A |
1 | /* |
2 | * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) | |
3 | * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved. | |
ba379fdc | 4 | * Copyright (C) 2009 Torch Mobile, Inc. |
9dae56ea A |
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" | |
f9bf01c6 | 26 | #include "Error.h" |
14957cd0 | 27 | #include "ExceptionHelpers.h" |
9dae56ea A |
28 | #include "JSArray.h" |
29 | #include "JSFunction.h" | |
30 | #include "JSString.h" | |
4e4e5a6f | 31 | #include "Lookup.h" |
9dae56ea A |
32 | #include "ObjectPrototype.h" |
33 | #include "RegExpMatchesArray.h" | |
34 | #include "RegExpObject.h" | |
35 | #include "RegExpPrototype.h" | |
36 | #include "RegExp.h" | |
4e4e5a6f | 37 | #include "RegExpCache.h" |
14957cd0 A |
38 | #include "UStringConcatenate.h" |
39 | #include <wtf/PassOwnPtr.h> | |
40 | ||
41 | #include <wtf/PassOwnPtr.h> | |
9dae56ea A |
42 | |
43 | namespace JSC { | |
44 | ||
4e4e5a6f A |
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&); | |
ba379fdc A |
60 | |
61 | static void setRegExpConstructorInput(ExecState*, JSObject*, JSValue); | |
62 | static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValue); | |
9dae56ea A |
63 | |
64 | } // namespace JSC | |
65 | ||
66 | #include "RegExpConstructor.lut.h" | |
67 | ||
68 | namespace JSC { | |
69 | ||
70 | ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor); | |
71 | ||
14957cd0 | 72 | const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::regExpConstructorTable }; |
9dae56ea A |
73 | |
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 | |
97 | @end | |
98 | */ | |
99 | ||
14957cd0 A |
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)) | |
9dae56ea | 103 | { |
14957cd0 A |
104 | ASSERT(inherits(&s_info)); |
105 | ||
9dae56ea | 106 | // ECMA 15.10.5.1 RegExp.prototype |
14957cd0 | 107 | putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly); |
9dae56ea A |
108 | |
109 | // no. of arguments for constructor | |
14957cd0 | 110 | putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(2), ReadOnly | DontDelete | DontEnum); |
9dae56ea A |
111 | } |
112 | ||
9dae56ea | 113 | RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data) |
14957cd0 | 114 | : JSArray(exec->globalData(), exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1, CreateInitialized) |
9dae56ea A |
115 | { |
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 | |
ba379fdc A |
121 | d->lastOvector().resize(offsetVectorSize); |
122 | memcpy(d->lastOvector().data(), data->lastOvector().data(), offsetVectorSize * sizeof(int)); | |
9dae56ea A |
123 | // d->multiline is not needed, and remains uninitialized |
124 | ||
4e4e5a6f | 125 | setSubclassData(d); |
9dae56ea A |
126 | } |
127 | ||
128 | RegExpMatchesArray::~RegExpMatchesArray() | |
129 | { | |
4e4e5a6f | 130 | delete static_cast<RegExpConstructorPrivate*>(subclassData()); |
9dae56ea A |
131 | } |
132 | ||
133 | void RegExpMatchesArray::fillArrayInstance(ExecState* exec) | |
134 | { | |
4e4e5a6f | 135 | RegExpConstructorPrivate* d = static_cast<RegExpConstructorPrivate*>(subclassData()); |
9dae56ea A |
136 | ASSERT(d); |
137 | ||
138 | unsigned lastNumSubpatterns = d->lastNumSubPatterns; | |
139 | ||
140 | for (unsigned i = 0; i <= lastNumSubpatterns; ++i) { | |
ba379fdc | 141 | int start = d->lastOvector()[2 * i]; |
9dae56ea | 142 | if (start >= 0) |
ba379fdc | 143 | JSArray::put(exec, i, jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start)); |
f9bf01c6 A |
144 | else |
145 | JSArray::put(exec, i, jsUndefined()); | |
9dae56ea A |
146 | } |
147 | ||
148 | PutPropertySlot slot; | |
14957cd0 | 149 | JSArray::put(exec, exec->propertyNames().index, jsNumber(d->lastOvector()[0]), slot); |
9dae56ea A |
150 | JSArray::put(exec, exec->propertyNames().input, jsString(exec, d->input), slot); |
151 | ||
152 | delete d; | |
4e4e5a6f | 153 | setSubclassData(0); |
9dae56ea A |
154 | } |
155 | ||
156 | JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const | |
157 | { | |
158 | return new (exec) RegExpMatchesArray(exec, d.get()); | |
159 | } | |
160 | ||
ba379fdc | 161 | JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) const |
9dae56ea | 162 | { |
ba379fdc A |
163 | if (!d->lastOvector().isEmpty() && i <= d->lastNumSubPatterns) { |
164 | int start = d->lastOvector()[2 * i]; | |
9dae56ea | 165 | if (start >= 0) |
ba379fdc | 166 | return jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start); |
9dae56ea A |
167 | } |
168 | return jsEmptyString(exec); | |
169 | } | |
170 | ||
ba379fdc | 171 | JSValue RegExpConstructor::getLastParen(ExecState* exec) const |
9dae56ea A |
172 | { |
173 | unsigned i = d->lastNumSubPatterns; | |
174 | if (i > 0) { | |
ba379fdc A |
175 | ASSERT(!d->lastOvector().isEmpty()); |
176 | int start = d->lastOvector()[2 * i]; | |
9dae56ea | 177 | if (start >= 0) |
ba379fdc | 178 | return jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start); |
9dae56ea A |
179 | } |
180 | return jsEmptyString(exec); | |
181 | } | |
182 | ||
ba379fdc | 183 | JSValue RegExpConstructor::getLeftContext(ExecState* exec) const |
9dae56ea | 184 | { |
ba379fdc A |
185 | if (!d->lastOvector().isEmpty()) |
186 | return jsSubstring(exec, d->lastInput, 0, d->lastOvector()[0]); | |
9dae56ea A |
187 | return jsEmptyString(exec); |
188 | } | |
189 | ||
ba379fdc | 190 | JSValue RegExpConstructor::getRightContext(ExecState* exec) const |
9dae56ea | 191 | { |
ba379fdc | 192 | if (!d->lastOvector().isEmpty()) |
14957cd0 | 193 | return jsSubstring(exec, d->lastInput, d->lastOvector()[1], d->lastInput.length() - d->lastOvector()[1]); |
9dae56ea A |
194 | return jsEmptyString(exec); |
195 | } | |
196 | ||
197 | bool RegExpConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | |
198 | { | |
199 | return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, slot); | |
200 | } | |
201 | ||
f9bf01c6 A |
202 | bool RegExpConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) |
203 | { | |
204 | return getStaticValueDescriptor<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, descriptor); | |
205 | } | |
206 | ||
4e4e5a6f | 207 | JSValue regExpConstructorDollar1(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 208 | { |
4e4e5a6f | 209 | return asRegExpConstructor(slotBase)->getBackref(exec, 1); |
9dae56ea A |
210 | } |
211 | ||
4e4e5a6f | 212 | JSValue regExpConstructorDollar2(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 213 | { |
4e4e5a6f | 214 | return asRegExpConstructor(slotBase)->getBackref(exec, 2); |
9dae56ea A |
215 | } |
216 | ||
4e4e5a6f | 217 | JSValue regExpConstructorDollar3(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 218 | { |
4e4e5a6f | 219 | return asRegExpConstructor(slotBase)->getBackref(exec, 3); |
9dae56ea A |
220 | } |
221 | ||
4e4e5a6f | 222 | JSValue regExpConstructorDollar4(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 223 | { |
4e4e5a6f | 224 | return asRegExpConstructor(slotBase)->getBackref(exec, 4); |
9dae56ea A |
225 | } |
226 | ||
4e4e5a6f | 227 | JSValue regExpConstructorDollar5(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 228 | { |
4e4e5a6f | 229 | return asRegExpConstructor(slotBase)->getBackref(exec, 5); |
9dae56ea A |
230 | } |
231 | ||
4e4e5a6f | 232 | JSValue regExpConstructorDollar6(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 233 | { |
4e4e5a6f | 234 | return asRegExpConstructor(slotBase)->getBackref(exec, 6); |
9dae56ea A |
235 | } |
236 | ||
4e4e5a6f | 237 | JSValue regExpConstructorDollar7(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 238 | { |
4e4e5a6f | 239 | return asRegExpConstructor(slotBase)->getBackref(exec, 7); |
9dae56ea A |
240 | } |
241 | ||
4e4e5a6f | 242 | JSValue regExpConstructorDollar8(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 243 | { |
4e4e5a6f | 244 | return asRegExpConstructor(slotBase)->getBackref(exec, 8); |
9dae56ea A |
245 | } |
246 | ||
4e4e5a6f | 247 | JSValue regExpConstructorDollar9(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 248 | { |
4e4e5a6f | 249 | return asRegExpConstructor(slotBase)->getBackref(exec, 9); |
9dae56ea A |
250 | } |
251 | ||
4e4e5a6f | 252 | JSValue regExpConstructorInput(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 253 | { |
4e4e5a6f | 254 | return jsString(exec, asRegExpConstructor(slotBase)->input()); |
9dae56ea A |
255 | } |
256 | ||
4e4e5a6f | 257 | JSValue regExpConstructorMultiline(ExecState*, JSValue slotBase, const Identifier&) |
9dae56ea | 258 | { |
4e4e5a6f | 259 | return jsBoolean(asRegExpConstructor(slotBase)->multiline()); |
9dae56ea A |
260 | } |
261 | ||
4e4e5a6f | 262 | JSValue regExpConstructorLastMatch(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 263 | { |
4e4e5a6f | 264 | return asRegExpConstructor(slotBase)->getBackref(exec, 0); |
9dae56ea A |
265 | } |
266 | ||
4e4e5a6f | 267 | JSValue regExpConstructorLastParen(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 268 | { |
4e4e5a6f | 269 | return asRegExpConstructor(slotBase)->getLastParen(exec); |
9dae56ea A |
270 | } |
271 | ||
4e4e5a6f | 272 | JSValue regExpConstructorLeftContext(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 273 | { |
4e4e5a6f | 274 | return asRegExpConstructor(slotBase)->getLeftContext(exec); |
9dae56ea A |
275 | } |
276 | ||
4e4e5a6f | 277 | JSValue regExpConstructorRightContext(ExecState* exec, JSValue slotBase, const Identifier&) |
9dae56ea | 278 | { |
4e4e5a6f | 279 | return asRegExpConstructor(slotBase)->getRightContext(exec); |
9dae56ea A |
280 | } |
281 | ||
ba379fdc | 282 | void RegExpConstructor::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) |
9dae56ea A |
283 | { |
284 | lookupPut<RegExpConstructor, InternalFunction>(exec, propertyName, value, ExecState::regExpConstructorTable(exec), this, slot); | |
285 | } | |
286 | ||
ba379fdc | 287 | void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValue value) |
9dae56ea A |
288 | { |
289 | asRegExpConstructor(baseObject)->setInput(value.toString(exec)); | |
290 | } | |
291 | ||
ba379fdc | 292 | void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValue value) |
9dae56ea A |
293 | { |
294 | asRegExpConstructor(baseObject)->setMultiline(value.toBoolean(exec)); | |
295 | } | |
14957cd0 | 296 | |
9dae56ea | 297 | // ECMA 15.10.4 |
14957cd0 | 298 | JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args) |
9dae56ea | 299 | { |
ba379fdc A |
300 | JSValue arg0 = args.at(0); |
301 | JSValue arg1 = args.at(1); | |
9dae56ea | 302 | |
14957cd0 | 303 | if (arg0.inherits(&RegExpObject::s_info)) { |
9dae56ea | 304 | if (!arg1.isUndefined()) |
14957cd0 | 305 | return throwError(exec, createTypeError(exec, "Cannot supply flags when constructing one RegExp from another.")); |
9dae56ea A |
306 | return asObject(arg0); |
307 | } | |
308 | ||
309 | UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec); | |
14957cd0 A |
310 | if (exec->hadException()) |
311 | return 0; | |
312 | ||
313 | RegExpFlags flags = NoFlags; | |
314 | if (!arg1.isUndefined()) { | |
315 | flags = regExpFlags(arg1.toString(exec)); | |
316 | if (exec->hadException()) | |
317 | return 0; | |
318 | if (flags == InvalidFlags) | |
319 | return throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor.")); | |
320 | } | |
9dae56ea | 321 | |
14957cd0 | 322 | RegExp* regExp = RegExp::create(&exec->globalData(), pattern, flags); |
9dae56ea | 323 | if (!regExp->isValid()) |
14957cd0 A |
324 | return throwError(exec, createSyntaxError(exec, regExp->errorMessage())); |
325 | return new (exec) RegExpObject(exec->lexicalGlobalObject(), globalObject->regExpStructure(), regExp); | |
9dae56ea A |
326 | } |
327 | ||
14957cd0 | 328 | static EncodedJSValue JSC_HOST_CALL constructWithRegExpConstructor(ExecState* exec) |
9dae56ea | 329 | { |
14957cd0 A |
330 | ArgList args(exec); |
331 | return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args)); | |
9dae56ea A |
332 | } |
333 | ||
334 | ConstructType RegExpConstructor::getConstructData(ConstructData& constructData) | |
335 | { | |
336 | constructData.native.function = constructWithRegExpConstructor; | |
337 | return ConstructTypeHost; | |
338 | } | |
339 | ||
340 | // ECMA 15.10.3 | |
14957cd0 | 341 | static EncodedJSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec) |
9dae56ea | 342 | { |
14957cd0 A |
343 | ArgList args(exec); |
344 | return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args)); | |
9dae56ea A |
345 | } |
346 | ||
347 | CallType RegExpConstructor::getCallData(CallData& callData) | |
348 | { | |
349 | callData.native.function = callRegExpConstructor; | |
350 | return CallTypeHost; | |
351 | } | |
352 | ||
353 | void RegExpConstructor::setInput(const UString& input) | |
354 | { | |
355 | d->input = input; | |
356 | } | |
357 | ||
358 | const UString& RegExpConstructor::input() const | |
359 | { | |
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). | |
362 | return d->input; | |
363 | } | |
364 | ||
365 | void RegExpConstructor::setMultiline(bool multiline) | |
366 | { | |
367 | d->multiline = multiline; | |
368 | } | |
369 | ||
370 | bool RegExpConstructor::multiline() const | |
371 | { | |
372 | return d->multiline; | |
373 | } | |
374 | ||
375 | } // namespace JSC |