• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
34 namespace JSC {
35 
36 static JSValuePtr regExpConstructorInput(ExecState*, const Identifier&, const PropertySlot&);
37 static JSValuePtr regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot&);
38 static JSValuePtr regExpConstructorLastMatch(ExecState*, const Identifier&, const PropertySlot&);
39 static JSValuePtr regExpConstructorLastParen(ExecState*, const Identifier&, const PropertySlot&);
40 static JSValuePtr regExpConstructorLeftContext(ExecState*, const Identifier&, const PropertySlot&);
41 static JSValuePtr regExpConstructorRightContext(ExecState*, const Identifier&, const PropertySlot&);
42 static JSValuePtr regExpConstructorDollar1(ExecState*, const Identifier&, const PropertySlot&);
43 static JSValuePtr regExpConstructorDollar2(ExecState*, const Identifier&, const PropertySlot&);
44 static JSValuePtr regExpConstructorDollar3(ExecState*, const Identifier&, const PropertySlot&);
45 static JSValuePtr regExpConstructorDollar4(ExecState*, const Identifier&, const PropertySlot&);
46 static JSValuePtr regExpConstructorDollar5(ExecState*, const Identifier&, const PropertySlot&);
47 static JSValuePtr regExpConstructorDollar6(ExecState*, const Identifier&, const PropertySlot&);
48 static JSValuePtr regExpConstructorDollar7(ExecState*, const Identifier&, const PropertySlot&);
49 static JSValuePtr regExpConstructorDollar8(ExecState*, const Identifier&, const PropertySlot&);
50 static JSValuePtr regExpConstructorDollar9(ExecState*, const Identifier&, const PropertySlot&);
51 
52 static void setRegExpConstructorInput(ExecState*, JSObject*, JSValuePtr);
53 static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValuePtr);
54 
55 } // namespace JSC
56 
57 #include "RegExpConstructor.lut.h"
58 
59 namespace JSC {
60 
61 ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor);
62 
63 const 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 
91 struct RegExpConstructorPrivate {
92     // Global search cache / settings
RegExpConstructorPrivateJSC::RegExpConstructorPrivate93     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 
RegExpConstructor(ExecState * exec,PassRefPtr<Structure> structure,RegExpPrototype * regExpPrototype)106 RegExpConstructor::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 */
performMatch(RegExp * r,const UString & s,int startOffset,int & position,int & length,int ** ovector)122 void 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 
RegExpMatchesArray(ExecState * exec,RegExpConstructorPrivate * data)142 RegExpMatchesArray::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 
~RegExpMatchesArray()157 RegExpMatchesArray::~RegExpMatchesArray()
158 {
159     delete static_cast<RegExpConstructorPrivate*>(lazyCreationData());
160 }
161 
fillArrayInstance(ExecState * exec)162 void 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 
arrayOfMatches(ExecState * exec) const183 JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const
184 {
185     return new (exec) RegExpMatchesArray(exec, d.get());
186 }
187 
getBackref(ExecState * exec,unsigned i) const188 JSValuePtr 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 
getLastParen(ExecState * exec) const198 JSValuePtr 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 
getLeftContext(ExecState * exec) const210 JSValuePtr 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 
getRightContext(ExecState * exec) const217 JSValuePtr 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 
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)224 bool RegExpConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
225 {
226     return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, slot);
227 }
228 
regExpConstructorDollar1(ExecState * exec,const Identifier &,const PropertySlot & slot)229 JSValuePtr regExpConstructorDollar1(ExecState* exec, const Identifier&, const PropertySlot& slot)
230 {
231     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 1);
232 }
233 
regExpConstructorDollar2(ExecState * exec,const Identifier &,const PropertySlot & slot)234 JSValuePtr regExpConstructorDollar2(ExecState* exec, const Identifier&, const PropertySlot& slot)
235 {
236     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 2);
237 }
238 
regExpConstructorDollar3(ExecState * exec,const Identifier &,const PropertySlot & slot)239 JSValuePtr regExpConstructorDollar3(ExecState* exec, const Identifier&, const PropertySlot& slot)
240 {
241     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 3);
242 }
243 
regExpConstructorDollar4(ExecState * exec,const Identifier &,const PropertySlot & slot)244 JSValuePtr regExpConstructorDollar4(ExecState* exec, const Identifier&, const PropertySlot& slot)
245 {
246     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 4);
247 }
248 
regExpConstructorDollar5(ExecState * exec,const Identifier &,const PropertySlot & slot)249 JSValuePtr regExpConstructorDollar5(ExecState* exec, const Identifier&, const PropertySlot& slot)
250 {
251     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 5);
252 }
253 
regExpConstructorDollar6(ExecState * exec,const Identifier &,const PropertySlot & slot)254 JSValuePtr regExpConstructorDollar6(ExecState* exec, const Identifier&, const PropertySlot& slot)
255 {
256     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 6);
257 }
258 
regExpConstructorDollar7(ExecState * exec,const Identifier &,const PropertySlot & slot)259 JSValuePtr regExpConstructorDollar7(ExecState* exec, const Identifier&, const PropertySlot& slot)
260 {
261     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 7);
262 }
263 
regExpConstructorDollar8(ExecState * exec,const Identifier &,const PropertySlot & slot)264 JSValuePtr regExpConstructorDollar8(ExecState* exec, const Identifier&, const PropertySlot& slot)
265 {
266     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 8);
267 }
268 
regExpConstructorDollar9(ExecState * exec,const Identifier &,const PropertySlot & slot)269 JSValuePtr regExpConstructorDollar9(ExecState* exec, const Identifier&, const PropertySlot& slot)
270 {
271     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 9);
272 }
273 
regExpConstructorInput(ExecState * exec,const Identifier &,const PropertySlot & slot)274 JSValuePtr regExpConstructorInput(ExecState* exec, const Identifier&, const PropertySlot& slot)
275 {
276     return jsString(exec, asRegExpConstructor(slot.slotBase())->input());
277 }
278 
regExpConstructorMultiline(ExecState *,const Identifier &,const PropertySlot & slot)279 JSValuePtr regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot& slot)
280 {
281     return jsBoolean(asRegExpConstructor(slot.slotBase())->multiline());
282 }
283 
regExpConstructorLastMatch(ExecState * exec,const Identifier &,const PropertySlot & slot)284 JSValuePtr regExpConstructorLastMatch(ExecState* exec, const Identifier&, const PropertySlot& slot)
285 {
286     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 0);
287 }
288 
regExpConstructorLastParen(ExecState * exec,const Identifier &,const PropertySlot & slot)289 JSValuePtr regExpConstructorLastParen(ExecState* exec, const Identifier&, const PropertySlot& slot)
290 {
291     return asRegExpConstructor(slot.slotBase())->getLastParen(exec);
292 }
293 
regExpConstructorLeftContext(ExecState * exec,const Identifier &,const PropertySlot & slot)294 JSValuePtr regExpConstructorLeftContext(ExecState* exec, const Identifier&, const PropertySlot& slot)
295 {
296     return asRegExpConstructor(slot.slotBase())->getLeftContext(exec);
297 }
298 
regExpConstructorRightContext(ExecState * exec,const Identifier &,const PropertySlot & slot)299 JSValuePtr regExpConstructorRightContext(ExecState* exec, const Identifier&, const PropertySlot& slot)
300 {
301     return asRegExpConstructor(slot.slotBase())->getRightContext(exec);
302 }
303 
put(ExecState * exec,const Identifier & propertyName,JSValuePtr value,PutPropertySlot & slot)304 void 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 
setRegExpConstructorInput(ExecState * exec,JSObject * baseObject,JSValuePtr value)309 void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValuePtr value)
310 {
311     asRegExpConstructor(baseObject)->setInput(value.toString(exec));
312 }
313 
setRegExpConstructorMultiline(ExecState * exec,JSObject * baseObject,JSValuePtr value)314 void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValuePtr value)
315 {
316     asRegExpConstructor(baseObject)->setMultiline(value.toBoolean(exec));
317 }
318 
319 // ECMA 15.10.4
constructRegExp(ExecState * exec,const ArgList & args)320 JSObject* 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 
constructWithRegExpConstructor(ExecState * exec,JSObject *,const ArgList & args)340 static JSObject* constructWithRegExpConstructor(ExecState* exec, JSObject*, const ArgList& args)
341 {
342     return constructRegExp(exec, args);
343 }
344 
getConstructData(ConstructData & constructData)345 ConstructType RegExpConstructor::getConstructData(ConstructData& constructData)
346 {
347     constructData.native.function = constructWithRegExpConstructor;
348     return ConstructTypeHost;
349 }
350 
351 // ECMA 15.10.3
callRegExpConstructor(ExecState * exec,JSObject *,JSValuePtr,const ArgList & args)352 static JSValuePtr callRegExpConstructor(ExecState* exec, JSObject*, JSValuePtr, const ArgList& args)
353 {
354     return constructRegExp(exec, args);
355 }
356 
getCallData(CallData & callData)357 CallType RegExpConstructor::getCallData(CallData& callData)
358 {
359     callData.native.function = callRegExpConstructor;
360     return CallTypeHost;
361 }
362 
setInput(const UString & input)363 void RegExpConstructor::setInput(const UString& input)
364 {
365     d->input = input;
366 }
367 
input() const368 const 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 
setMultiline(bool multiline)375 void RegExpConstructor::setMultiline(bool multiline)
376 {
377     d->multiline = multiline;
378 }
379 
multiline() const380 bool RegExpConstructor::multiline() const
381 {
382     return d->multiline;
383 }
384 
385 } // namespace JSC
386