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 "RegExpObject.h"
23
24#include "Error.h"
25#include "ExceptionHelpers.h"
26#include "JSArray.h"
27#include "JSGlobalObject.h"
28#include "JSString.h"
29#include "Lookup.h"
30#include "RegExpConstructor.h"
31#include "RegExpPrototype.h"
32#include "UStringConcatenate.h"
33#include <wtf/PassOwnPtr.h>
34
35namespace JSC {
36
37static JSValue regExpObjectGlobal(ExecState*, JSValue, const Identifier&);
38static JSValue regExpObjectIgnoreCase(ExecState*, JSValue, const Identifier&);
39static JSValue regExpObjectMultiline(ExecState*, JSValue, const Identifier&);
40static JSValue regExpObjectSource(ExecState*, JSValue, const Identifier&);
41static JSValue regExpObjectLastIndex(ExecState*, JSValue, const Identifier&);
42static void setRegExpObjectLastIndex(ExecState*, JSObject*, JSValue);
43
44} // namespace JSC
45
46#include "RegExpObject.lut.h"
47
48namespace JSC {
49
50ASSERT_CLASS_FITS_IN_CELL(RegExpObject);
51
52const ClassInfo RegExpObject::s_info = { "RegExp", &JSObjectWithGlobalObject::s_info, 0, ExecState::regExpTable };
53
54/* Source for RegExpObject.lut.h
55@begin regExpTable
56    global        regExpObjectGlobal       DontDelete|ReadOnly|DontEnum
57    ignoreCase    regExpObjectIgnoreCase   DontDelete|ReadOnly|DontEnum
58    multiline     regExpObjectMultiline    DontDelete|ReadOnly|DontEnum
59    source        regExpObjectSource       DontDelete|ReadOnly|DontEnum
60    lastIndex     regExpObjectLastIndex    DontDelete|DontEnum
61@end
62*/
63
64RegExpObject::RegExpObject(JSGlobalObject* globalObject, Structure* structure, NonNullPassRefPtr<RegExp> regExp)
65    : JSObjectWithGlobalObject(globalObject, structure)
66    , d(adoptPtr(new RegExpObjectData(regExp)))
67{
68    ASSERT(inherits(&s_info));
69}
70
71RegExpObject::~RegExpObject()
72{
73}
74
75void RegExpObject::markChildren(MarkStack& markStack)
76{
77    Base::markChildren(markStack);
78    if (UNLIKELY(!d->lastIndex.get().isInt32()))
79        markStack.append(&d->lastIndex);
80}
81
82bool RegExpObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
83{
84    return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, slot);
85}
86
87bool RegExpObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
88{
89    return getStaticValueDescriptor<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, descriptor);
90}
91
92JSValue regExpObjectGlobal(ExecState*, JSValue slotBase, const Identifier&)
93{
94    return jsBoolean(asRegExpObject(slotBase)->regExp()->global());
95}
96
97JSValue regExpObjectIgnoreCase(ExecState*, JSValue slotBase, const Identifier&)
98{
99    return jsBoolean(asRegExpObject(slotBase)->regExp()->ignoreCase());
100}
101
102JSValue regExpObjectMultiline(ExecState*, JSValue slotBase, const Identifier&)
103{
104    return jsBoolean(asRegExpObject(slotBase)->regExp()->multiline());
105}
106
107JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, const Identifier&)
108{
109    return jsString(exec, asRegExpObject(slotBase)->regExp()->pattern());
110}
111
112JSValue regExpObjectLastIndex(ExecState*, JSValue slotBase, const Identifier&)
113{
114    return asRegExpObject(slotBase)->getLastIndex();
115}
116
117void RegExpObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
118{
119    lookupPut<RegExpObject, JSObject>(exec, propertyName, value, ExecState::regExpTable(exec), this, slot);
120}
121
122void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value)
123{
124    asRegExpObject(baseObject)->setLastIndex(exec->globalData(), value);
125}
126
127JSValue RegExpObject::test(ExecState* exec)
128{
129    return jsBoolean(match(exec));
130}
131
132JSValue RegExpObject::exec(ExecState* exec)
133{
134    if (match(exec))
135        return exec->lexicalGlobalObject()->regExpConstructor()->arrayOfMatches(exec);
136    return jsNull();
137}
138
139// Shared implementation used by test and exec.
140bool RegExpObject::match(ExecState* exec)
141{
142    RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
143    UString input = exec->argument(0).toString(exec);
144
145    if (!regExp()->global()) {
146        int position;
147        int length;
148        regExpConstructor->performMatch(d->regExp.get(), input, 0, position, length);
149        return position >= 0;
150    }
151
152    JSValue jsLastIndex = getLastIndex();
153    unsigned lastIndex;
154    if (LIKELY(jsLastIndex.isUInt32())) {
155        lastIndex = jsLastIndex.asUInt32();
156        if (lastIndex > input.length()) {
157            setLastIndex(0);
158            return false;
159        }
160    } else {
161        double doubleLastIndex = jsLastIndex.toInteger(exec);
162        if (doubleLastIndex < 0 || doubleLastIndex > input.length()) {
163            setLastIndex(0);
164            return false;
165        }
166        lastIndex = static_cast<unsigned>(doubleLastIndex);
167    }
168
169    int position;
170    int length = 0;
171    regExpConstructor->performMatch(d->regExp.get(), input, lastIndex, position, length);
172    if (position < 0) {
173        setLastIndex(0);
174        return false;
175    }
176
177    setLastIndex(position + length);
178    return true;
179}
180
181} // namespace JSC
182