Fix build by adding all (hopefully) the missing includes.
[WebKit-https.git] / JavaScriptCore / kjs / RegExpConstructor.cpp
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 #include "RegExpConstructor.lut.h"
24
25 #include "ArrayPrototype.h"
26 #include "JSArray.h"
27 #include "JSFunction.h"
28 #include "JSString.h"
29 #include "ObjectPrototype.h"
30 #include "RegExpObject.h"
31 #include "RegExpPrototype.h"
32 #include "regexp.h"
33
34 namespace KJS {
35
36 const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, 0, ExecState::regExpConstructorTable };
37
38 /* Source for RegExpConstructor.lut.h
39 @begin regExpConstructorTable
40   input           RegExpConstructor::Input          None
41   $_              RegExpConstructor::Input          DontEnum
42   multiline       RegExpConstructor::Multiline      None
43   $*              RegExpConstructor::Multiline      DontEnum
44   lastMatch       RegExpConstructor::LastMatch      DontDelete|ReadOnly
45   $&              RegExpConstructor::LastMatch      DontDelete|ReadOnly|DontEnum
46   lastParen       RegExpConstructor::LastParen      DontDelete|ReadOnly
47   $+              RegExpConstructor::LastParen      DontDelete|ReadOnly|DontEnum
48   leftContext     RegExpConstructor::LeftContext    DontDelete|ReadOnly
49   $`              RegExpConstructor::LeftContext    DontDelete|ReadOnly|DontEnum
50   rightContext    RegExpConstructor::RightContext   DontDelete|ReadOnly
51   $'              RegExpConstructor::RightContext   DontDelete|ReadOnly|DontEnum
52   $1              RegExpConstructor::Dollar1        DontDelete|ReadOnly
53   $2              RegExpConstructor::Dollar2        DontDelete|ReadOnly
54   $3              RegExpConstructor::Dollar3        DontDelete|ReadOnly
55   $4              RegExpConstructor::Dollar4        DontDelete|ReadOnly
56   $5              RegExpConstructor::Dollar5        DontDelete|ReadOnly
57   $6              RegExpConstructor::Dollar6        DontDelete|ReadOnly
58   $7              RegExpConstructor::Dollar7        DontDelete|ReadOnly
59   $8              RegExpConstructor::Dollar8        DontDelete|ReadOnly
60   $9              RegExpConstructor::Dollar9        DontDelete|ReadOnly
61 @end
62 */
63
64 struct RegExpConstructorPrivate {
65   // Global search cache / settings
66   RegExpConstructorPrivate() : lastNumSubPatterns(0), multiline(false) { }
67   UString lastInput;
68   OwnArrayPtr<int> lastOvector;
69   unsigned lastNumSubPatterns : 31;
70   bool multiline              : 1;
71 };
72
73 RegExpConstructor::RegExpConstructor(ExecState* exec, FunctionPrototype* funcProto, RegExpPrototype* regProto)
74   : InternalFunction(funcProto, Identifier(exec, "RegExp"))
75   , d(new RegExpConstructorPrivate)
76 {
77   // ECMA 15.10.5.1 RegExp.prototype
78   putDirect(exec->propertyNames().prototype, regProto, DontEnum | DontDelete | ReadOnly);
79
80   // no. of arguments for constructor
81   putDirect(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly | DontDelete | DontEnum);
82 }
83
84 /* 
85   To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular
86   expression matching through the performMatch function. We use cached results to calculate, 
87   e.g., RegExp.lastMatch and RegExp.leftParen.
88 */
89 void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector)
90 {
91   OwnArrayPtr<int> tmpOvector;
92   position = r->match(s, startOffset, &tmpOvector);
93
94   if (ovector)
95     *ovector = tmpOvector.get();
96   
97   if (position != -1) {
98     ASSERT(tmpOvector);
99
100     length = tmpOvector[1] - tmpOvector[0];
101
102     d->lastInput = s;
103     d->lastOvector.set(tmpOvector.release());
104     d->lastNumSubPatterns = r->numSubpatterns();
105   }
106 }
107
108 class RegExpMatchesArray : public JSArray {
109 public:
110     RegExpMatchesArray(ExecState*, RegExpConstructorPrivate*);
111     virtual ~RegExpMatchesArray();
112
113 private:
114     virtual bool getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { if (lazyCreationData()) fillArrayInstance(exec); return JSArray::getOwnPropertySlot(exec, propertyName, slot); }
115     virtual bool getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) { if (lazyCreationData()) fillArrayInstance(exec); return JSArray::getOwnPropertySlot(exec, propertyName, slot); }
116     virtual void put(ExecState* exec, const Identifier& propertyName, JSValue* v) { if (lazyCreationData()) fillArrayInstance(exec); JSArray::put(exec, propertyName, v); }
117     virtual void put(ExecState* exec, unsigned propertyName, JSValue* v) { if (lazyCreationData()) fillArrayInstance(exec); JSArray::put(exec, propertyName, v); }
118     virtual bool deleteProperty(ExecState* exec, const Identifier& propertyName) { if (lazyCreationData()) fillArrayInstance(exec); return JSArray::deleteProperty(exec, propertyName); }
119     virtual bool deleteProperty(ExecState* exec, unsigned propertyName) { if (lazyCreationData()) fillArrayInstance(exec); return JSArray::deleteProperty(exec, propertyName); }
120     virtual void getPropertyNames(ExecState* exec, PropertyNameArray& arr) { if (lazyCreationData()) fillArrayInstance(exec); JSArray::getPropertyNames(exec, arr); }
121
122     void fillArrayInstance(ExecState*);
123 };
124
125 RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data)
126     : JSArray(exec->lexicalGlobalObject()->arrayPrototype(), data->lastNumSubPatterns + 1)
127 {
128     RegExpConstructorPrivate* d = new RegExpConstructorPrivate;
129     d->lastInput = data->lastInput;
130     d->lastNumSubPatterns = data->lastNumSubPatterns;
131     unsigned offsetVectorSize = (data->lastNumSubPatterns + 1) * 2; // only copying the result part of the vector
132     d->lastOvector.set(new int[offsetVectorSize]);
133     memcpy(d->lastOvector.get(), data->lastOvector.get(), offsetVectorSize * sizeof(int));
134     // d->multiline is not needed, and remains uninitialized
135
136     setLazyCreationData(d);
137 }
138
139 RegExpMatchesArray::~RegExpMatchesArray()
140 {
141     delete static_cast<RegExpConstructorPrivate*>(lazyCreationData());
142 }
143
144 void RegExpMatchesArray::fillArrayInstance(ExecState* exec)
145 {
146     RegExpConstructorPrivate* d = static_cast<RegExpConstructorPrivate*>(lazyCreationData());
147     ASSERT(d);
148
149     unsigned lastNumSubpatterns = d->lastNumSubPatterns;
150
151     for (unsigned i = 0; i <= lastNumSubpatterns; ++i) {
152         int start = d->lastOvector[2 * i];
153         if (start >= 0)
154             JSArray::put(exec, i, jsString(exec, d->lastInput.substr(start, d->lastOvector[2 * i + 1] - start)));
155     }
156     JSArray::put(exec, exec->propertyNames().index, jsNumber(exec, d->lastOvector[0]));
157     JSArray::put(exec, exec->propertyNames().input, jsString(exec, d->lastInput));
158
159     delete d;
160     setLazyCreationData(0);
161 }
162
163 JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const
164 {
165     return new (exec) RegExpMatchesArray(exec, d.get());
166 }
167
168 JSValue* RegExpConstructor::getBackref(ExecState* exec, unsigned i) const
169 {
170   if (d->lastOvector && i <= d->lastNumSubPatterns)
171     return jsString(exec, d->lastInput.substr(d->lastOvector[2 * i], d->lastOvector[2 * i + 1] - d->lastOvector[2 * i]));
172   return jsString(exec, "");
173 }
174
175 JSValue* RegExpConstructor::getLastParen(ExecState* exec) const
176 {
177   unsigned i = d->lastNumSubPatterns;
178   if (i > 0) {
179     ASSERT(d->lastOvector);
180     return jsString(exec, d->lastInput.substr(d->lastOvector[2 * i], d->lastOvector[2 * i + 1] - d->lastOvector[2 * i]));
181   }
182   return jsString(exec, "");
183 }
184
185 JSValue* RegExpConstructor::getLeftContext(ExecState* exec) const
186 {
187   if (d->lastOvector)
188     return jsString(exec, d->lastInput.substr(0, d->lastOvector[0]));
189   return jsString(exec, "");
190 }
191
192 JSValue* RegExpConstructor::getRightContext(ExecState* exec) const
193 {
194   if (d->lastOvector) {
195     UString s = d->lastInput;
196     return jsString(exec, s.substr(d->lastOvector[1], s.size() - d->lastOvector[1]));
197   }
198   return jsString(exec, "");
199 }
200
201 bool RegExpConstructor::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
202 {
203   return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, slot);
204 }
205
206 JSValue *RegExpConstructor::getValueProperty(ExecState* exec, int token) const
207 {
208   switch (token) {
209     case Dollar1:
210       return getBackref(exec, 1);
211     case Dollar2:
212       return getBackref(exec, 2);
213     case Dollar3:
214       return getBackref(exec, 3);
215     case Dollar4:
216       return getBackref(exec, 4);
217     case Dollar5:
218       return getBackref(exec, 5);
219     case Dollar6:
220       return getBackref(exec, 6);
221     case Dollar7:
222       return getBackref(exec, 7);
223     case Dollar8:
224       return getBackref(exec, 8);
225     case Dollar9:
226       return getBackref(exec, 9);
227     case Input:
228       return jsString(exec, d->lastInput);
229     case Multiline:
230       return jsBoolean(d->multiline);
231     case LastMatch:
232       return getBackref(exec, 0);
233     case LastParen:
234       return getLastParen(exec);
235     case LeftContext:
236       return getLeftContext(exec);
237     case RightContext:
238       return getRightContext(exec);
239     default:
240       ASSERT_NOT_REACHED();
241   }
242
243   return jsString(exec, "");
244 }
245
246 void RegExpConstructor::put(ExecState *exec, const Identifier &propertyName, JSValue *value)
247 {
248     lookupPut<RegExpConstructor, InternalFunction>(exec, propertyName, value, ExecState::regExpConstructorTable(exec), this);
249 }
250
251 void RegExpConstructor::putValueProperty(ExecState *exec, int token, JSValue *value)
252 {
253   switch (token) {
254     case Input:
255       d->lastInput = value->toString(exec);
256       break;
257     case Multiline:
258       d->multiline = value->toBoolean(exec);
259       break;
260     default:
261       ASSERT(0);
262   }
263 }
264   
265 // ECMA 15.10.4
266 static JSObject* constructRegExp(ExecState* exec, const ArgList& args)
267 {
268   JSValue* arg0 = args[0];
269   JSValue* arg1 = args[1];
270   
271   if (arg0->isObject(&RegExpObject::info)) {
272     if (!arg1->isUndefined())
273       return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another.");
274     return static_cast<JSObject*>(arg0);
275   }
276   
277   UString pattern = arg0->isUndefined() ? UString("") : arg0->toString(exec);
278   UString flags = arg1->isUndefined() ? UString("") : arg1->toString(exec);
279   
280   RefPtr<RegExp> regExp = RegExp::create(pattern, flags);
281   return regExp->isValid()
282     ? new (exec) RegExpObject(exec->lexicalGlobalObject()->regExpPrototype(), regExp.release())
283     : throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage()));
284 }
285
286 static JSObject* constructWithRegExpConstructor(ExecState* exec, JSObject*, const ArgList& args)
287 {
288     return constructRegExp(exec, args);
289 }
290
291 ConstructType RegExpConstructor::getConstructData(ConstructData& constructData)
292 {
293     constructData.native.function = constructWithRegExpConstructor;
294     return ConstructTypeNative;
295 }
296
297 // ECMA 15.10.3
298 static JSValue* callRegExpConstructor(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
299 {
300     return constructRegExp(exec, args);
301 }
302
303 CallType RegExpConstructor::getCallData(CallData& callData)
304 {
305     callData.native.function = callRegExpConstructor;
306     return CallTypeNative;
307 }
308
309 const UString& RegExpConstructor::input() const
310 {
311     // Can detect a distinct initial state that is invisible to JavaScript, by checking for null
312     // state (since jsString turns null strings to empty strings).
313     return d->lastInput;
314 }
315
316 } // namespace KJS