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 "JSArray.h" |
26 | #include "JSGlobalObject.h" |
27 | #include "JSString.h" |
28 | #include "RegExpConstructor.h" |
29 | #include "RegExpPrototype.h" |
30 | |
31 | namespace JSC { |
32 | |
33 | static JSValue regExpObjectGlobal(ExecState*, const Identifier&, const PropertySlot&); |
34 | static JSValue regExpObjectIgnoreCase(ExecState*, const Identifier&, const PropertySlot&); |
35 | static JSValue regExpObjectMultiline(ExecState*, const Identifier&, const PropertySlot&); |
36 | static JSValue regExpObjectSource(ExecState*, const Identifier&, const PropertySlot&); |
37 | static JSValue regExpObjectLastIndex(ExecState*, const Identifier&, const PropertySlot&); |
38 | static void setRegExpObjectLastIndex(ExecState*, JSObject*, JSValue); |
39 | |
40 | } // namespace JSC |
41 | |
42 | #include "RegExpObject.lut.h" |
43 | |
44 | namespace JSC { |
45 | |
46 | ASSERT_CLASS_FITS_IN_CELL(RegExpObject); |
47 | |
48 | const ClassInfo RegExpObject::info = { .className: "RegExp" , .parentClass: 0, .staticPropHashTable: 0, .classPropHashTableGetterFunction: ExecState::regExpTable }; |
49 | |
50 | /* Source for RegExpObject.lut.h |
51 | @begin regExpTable |
52 | global regExpObjectGlobal DontDelete|ReadOnly|DontEnum |
53 | ignoreCase regExpObjectIgnoreCase DontDelete|ReadOnly|DontEnum |
54 | multiline regExpObjectMultiline DontDelete|ReadOnly|DontEnum |
55 | source regExpObjectSource DontDelete|ReadOnly|DontEnum |
56 | lastIndex regExpObjectLastIndex DontDelete|DontEnum |
57 | @end |
58 | */ |
59 | |
60 | RegExpObject::RegExpObject(NonNullPassRefPtr<Structure> structure, NonNullPassRefPtr<RegExp> regExp) |
61 | : JSObject(structure) |
62 | , d(new RegExpObjectData(regExp, 0)) |
63 | { |
64 | } |
65 | |
66 | RegExpObject::~RegExpObject() |
67 | { |
68 | } |
69 | |
70 | bool RegExpObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) |
71 | { |
72 | return getStaticValueSlot<RegExpObject, JSObject>(exec, table: ExecState::regExpTable(callFrame: exec), thisObj: this, propertyName, slot); |
73 | } |
74 | |
75 | bool RegExpObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) |
76 | { |
77 | return getStaticValueDescriptor<RegExpObject, JSObject>(exec, table: ExecState::regExpTable(callFrame: exec), thisObj: this, propertyName, descriptor); |
78 | } |
79 | |
80 | JSValue regExpObjectGlobal(ExecState*, const Identifier&, const PropertySlot& slot) |
81 | { |
82 | return jsBoolean(b: asRegExpObject(value: slot.slotBase())->regExp()->global()); |
83 | } |
84 | |
85 | JSValue regExpObjectIgnoreCase(ExecState*, const Identifier&, const PropertySlot& slot) |
86 | { |
87 | return jsBoolean(b: asRegExpObject(value: slot.slotBase())->regExp()->ignoreCase()); |
88 | } |
89 | |
90 | JSValue regExpObjectMultiline(ExecState*, const Identifier&, const PropertySlot& slot) |
91 | { |
92 | return jsBoolean(b: asRegExpObject(value: slot.slotBase())->regExp()->multiline()); |
93 | } |
94 | |
95 | JSValue regExpObjectSource(ExecState* exec, const Identifier&, const PropertySlot& slot) |
96 | { |
97 | return jsString(exec, s: asRegExpObject(value: slot.slotBase())->regExp()->pattern()); |
98 | } |
99 | |
100 | JSValue regExpObjectLastIndex(ExecState* exec, const Identifier&, const PropertySlot& slot) |
101 | { |
102 | return jsNumber(exec, d: asRegExpObject(value: slot.slotBase())->lastIndex()); |
103 | } |
104 | |
105 | void RegExpObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) |
106 | { |
107 | lookupPut<RegExpObject, JSObject>(exec, propertyName, value, table: ExecState::regExpTable(callFrame: exec), thisObj: this, slot); |
108 | } |
109 | |
110 | void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value) |
111 | { |
112 | asRegExpObject(value: baseObject)->setLastIndex(value.toInteger(exec)); |
113 | } |
114 | |
115 | JSValue RegExpObject::test(ExecState* exec, const ArgList& args) |
116 | { |
117 | return jsBoolean(b: match(exec, args)); |
118 | } |
119 | |
120 | JSValue RegExpObject::exec(ExecState* exec, const ArgList& args) |
121 | { |
122 | if (match(exec, args)) |
123 | return exec->lexicalGlobalObject()->regExpConstructor()->arrayOfMatches(exec); |
124 | return jsNull(); |
125 | } |
126 | |
127 | static JSValue JSC_HOST_CALL callRegExpObject(ExecState* exec, JSObject* function, JSValue, const ArgList& args) |
128 | { |
129 | return asRegExpObject(value: function)->exec(exec, args); |
130 | } |
131 | |
132 | CallType RegExpObject::getCallData(CallData& callData) |
133 | { |
134 | callData.native.function = callRegExpObject; |
135 | return CallTypeHost; |
136 | } |
137 | |
138 | // Shared implementation used by test and exec. |
139 | bool RegExpObject::match(ExecState* exec, const ArgList& args) |
140 | { |
141 | RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); |
142 | |
143 | UString input = args.isEmpty() ? regExpConstructor->input() : args.at(idx: 0).toString(exec); |
144 | if (input.isNull()) { |
145 | throwError(exec, GeneralError, message: makeString(string1: "No input to " , string2: toString(exec), string3: "." )); |
146 | return false; |
147 | } |
148 | |
149 | if (!regExp()->global()) { |
150 | int position; |
151 | int length; |
152 | regExpConstructor->performMatch(r: d->regExp.get(), s: input, startOffset: 0, position, length); |
153 | return position >= 0; |
154 | } |
155 | |
156 | if (d->lastIndex < 0 || d->lastIndex > input.size()) { |
157 | d->lastIndex = 0; |
158 | return false; |
159 | } |
160 | |
161 | int position; |
162 | int length = 0; |
163 | regExpConstructor->performMatch(r: d->regExp.get(), s: input, startOffset: static_cast<int>(d->lastIndex), position, length); |
164 | if (position < 0) { |
165 | d->lastIndex = 0; |
166 | return false; |
167 | } |
168 | |
169 | d->lastIndex = position + length; |
170 | return true; |
171 | } |
172 | |
173 | } // namespace JSC |
174 | |