1 /*
2 This file is part of the KDE libraries
3 Copyright 2012 Bernd Buschinski <b.buschinski@googlemail.com>
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.1 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, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "propertydescriptor.h"
20 #include "object.h"
21 #include "operations.h"
22
23 #include <stdio.h>
24
25 namespace KJS
26 {
27
PropertyDescriptor()28 PropertyDescriptor::PropertyDescriptor()
29 : m_attributes(DontEnum | DontDelete | ReadOnly),
30 m_setAttributes(0),
31 m_value(nullptr),
32 m_getter(nullptr),
33 m_setter(nullptr)
34 {
35 }
36
37 //ECMAScript Edition 5.1r6 - 8.10.1
isAccessorDescriptor() const38 bool PropertyDescriptor::isAccessorDescriptor() const
39 {
40 return (m_getter || m_setter);
41 }
42
43 //ECMAScript Edition 5.1r6 - 8.10.2
isDataDescriptor() const44 bool PropertyDescriptor::isDataDescriptor() const
45 {
46 if (!m_value && !(writableSet())) {
47 return false;
48 }
49 return true;
50 }
51
52 //ECMAScript Edition 5.1r6 - 8.10.3
isGenericDescriptor() const53 bool PropertyDescriptor::isGenericDescriptor() const
54 {
55 return (!isAccessorDescriptor() && !isDataDescriptor());
56 }
57
58 //ECMAScript Edition 5.1r6 - 8.10.4 - FromPropertyDescriptor
fromPropertyDescriptor(ExecState * exec)59 JSObject *PropertyDescriptor::fromPropertyDescriptor(ExecState *exec)
60 {
61 JSObject *ret = new JSObject(exec->lexicalInterpreter()->builtinObjectPrototype());
62
63 if (isDataDescriptor()) {
64 ret->put(exec, exec->propertyNames().writable, jsBoolean(writable()));
65 ret->put(exec, exec->propertyNames().value, value() ? value() : jsUndefined());
66 } else {
67 ret->put(exec, exec->propertyNames().get, getter() ? getter() : jsUndefined());
68 ret->put(exec, exec->propertyNames().set, setter() ? setter() : jsUndefined());
69 }
70
71 ret->put(exec, exec->propertyNames().enumerable, jsBoolean(enumerable()));
72 ret->put(exec, exec->propertyNames().configurable, jsBoolean(configurable()));
73
74 return ret;
75 }
76
77 //ECMAScript Edition 5.1r6 - 8.10.5 - ToPropertyDescriptor
setPropertyDescriptorFromObject(ExecState * exec,JSValue * jsValue)78 bool PropertyDescriptor::setPropertyDescriptorFromObject(ExecState *exec, JSValue *jsValue)
79 {
80 JSObject *obj = JSValue::getObject(jsValue);
81 if (!obj) {
82 throwError(exec, TypeError, "not an Object");
83 return false;
84 }
85
86 if (obj->hasProperty(exec, exec->propertyNames().enumerable)) {
87 setEnumerable(JSValue::toBoolean(obj->get(exec, exec->propertyNames().enumerable), exec));
88 }
89
90 if (obj->hasProperty(exec, exec->propertyNames().configurable)) {
91 setConfigureable(JSValue::toBoolean(obj->get(exec, exec->propertyNames().configurable), exec));
92 }
93
94 if (obj->hasProperty(exec, exec->propertyNames().value)) {
95 setValue(obj->get(exec, exec->propertyNames().value));
96 }
97
98 if (obj->hasProperty(exec, exec->propertyNames().writable)) {
99 setWritable(JSValue::toBoolean(obj->get(exec, exec->propertyNames().writable), exec));
100 }
101
102 if (obj->hasProperty(exec, exec->propertyNames().get)) {
103 JSValue *getter = obj->get(exec, exec->propertyNames().get);
104 if (!JSValue::isUndefined(getter)) {
105 if (!JSValue::implementsCall(getter)) {
106 throwError(exec, TypeError, "Getter: \'" + JSValue::toString(getter, exec) + "\' is not Callable");
107 return false;
108 }
109 }
110 setGetter(getter);
111 }
112
113 if (obj->hasProperty(exec, exec->propertyNames().set)) {
114 JSValue *setter = obj->get(exec, exec->propertyNames().set);
115 if (!JSValue::isUndefined(setter)) {
116 if (!JSValue::implementsCall(setter)) {
117 throwError(exec, TypeError, "Setter: \'" + JSValue::toString(setter, exec) + "\' is not Callable");
118 return false;
119 }
120 }
121 setSetter(setter);
122 }
123
124 if (getter() || setter()) {
125 if (value() || writableSet()) {
126 throwError(exec, TypeError, "can not mix accessor descriptor and data descriptor");
127 return false;
128 }
129 }
130 return true;
131 }
132
setPropertyDescriptorValues(ExecState *,JSValue * value,unsigned int attributes)133 bool PropertyDescriptor::setPropertyDescriptorValues(ExecState *, JSValue *value, unsigned int attributes)
134 {
135 setEnumerable(!(attributes & DontEnum));
136 setConfigureable(!(attributes & DontDelete));
137
138 if (!value) {
139 return false;
140 }
141 if (JSValue::isUndefined(value) || JSValue::type(value) != GetterSetterType) {
142 setValue(value);
143 setWritable(!(attributes & ReadOnly));
144 } else {
145 GetterSetterImp *gs = static_cast<GetterSetterImp *>(value);
146 setGetter(gs->getGetter() ? gs->getGetter() : jsUndefined());
147 setSetter(gs->getSetter() ? gs->getSetter() : jsUndefined());
148 }
149 return true;
150 }
151
configurable() const152 bool PropertyDescriptor::configurable() const
153 {
154 return !(m_attributes & DontDelete);
155 }
156
enumerable() const157 bool PropertyDescriptor::enumerable() const
158 {
159 return !(m_attributes & DontEnum);
160 }
161
writable() const162 bool PropertyDescriptor::writable() const
163 {
164 return !(m_attributes & ReadOnly);
165 }
166
configureSet() const167 bool PropertyDescriptor::configureSet() const
168 {
169 return m_setAttributes & ConfigurableSet;
170 }
171
enumerableSet() const172 bool PropertyDescriptor::enumerableSet() const
173 {
174 return m_setAttributes & EnumerableSet;
175 }
176
writableSet() const177 bool PropertyDescriptor::writableSet() const
178 {
179 return m_setAttributes & WritableSet;
180 }
181
getter() const182 JSValue *PropertyDescriptor::getter() const
183 {
184 return m_getter;
185 }
186
setter() const187 JSValue *PropertyDescriptor::setter() const
188 {
189 return m_setter;
190 }
191
value() const192 JSValue *PropertyDescriptor::value() const
193 {
194 return m_value;
195 }
196
setEnumerable(bool enumerable)197 void PropertyDescriptor::setEnumerable(bool enumerable)
198 {
199 if (enumerable) {
200 m_attributes &= ~DontEnum;
201 } else {
202 m_attributes |= DontEnum;
203 }
204 m_setAttributes |= EnumerableSet;
205 }
206
setConfigureable(bool configurable)207 void PropertyDescriptor::setConfigureable(bool configurable)
208 {
209 if (configurable) {
210 m_attributes &= ~DontDelete;
211 } else {
212 m_attributes |= DontDelete;
213 }
214 m_setAttributes |= ConfigurableSet;
215 }
216
setValue(JSValue * value)217 void PropertyDescriptor::setValue(JSValue *value)
218 {
219 m_value = value;
220 }
221
setWritable(bool writable)222 void PropertyDescriptor::setWritable(bool writable)
223 {
224 if (writable) {
225 m_attributes &= ~ReadOnly;
226 } else {
227 m_attributes |= ReadOnly;
228 }
229 m_setAttributes |= WritableSet;
230 }
231
setGetter(JSValue * getter)232 void PropertyDescriptor::setGetter(JSValue *getter)
233 {
234 m_getter = getter;
235 m_attributes &= ~ReadOnly;
236 }
237
setSetter(JSValue * setter)238 void PropertyDescriptor::setSetter(JSValue *setter)
239 {
240 m_setter = setter;
241 m_attributes &= ~ReadOnly;
242 }
243
attributes() const244 unsigned int PropertyDescriptor::attributes() const
245 {
246 return m_attributes;
247 }
248
isEmpty() const249 bool PropertyDescriptor::isEmpty() const
250 {
251 return !m_setAttributes && !m_getter && !m_setter && !m_value;
252 }
253
compareValue(ExecState * exec,JSValue * a,JSValue * b)254 inline bool compareValue(ExecState *exec, JSValue *a, JSValue *b)
255 {
256 return (a == b || (a && b && sameValue(exec, a, b)));
257 }
258
259 // different from compareValue, if "own" getter/setter is missing (is 0) we are still the same
compareFunction(ExecState * exec,JSValue * a,JSValue * b)260 inline bool compareFunction(ExecState *exec, JSValue *a, JSValue *b)
261 {
262 return (a == b || (b != nullptr && a == nullptr) || (a && b && sameValue(exec, a, b)));
263 }
264
equalTo(ExecState * exec,PropertyDescriptor & other) const265 bool PropertyDescriptor::equalTo(ExecState *exec, PropertyDescriptor &other) const
266 {
267 return (compareValue(exec, m_value, other.value()) &&
268 compareFunction(exec, m_getter, other.getter()) &&
269 compareFunction(exec, m_setter, other.setter()) &&
270 attributes() == other.attributes());
271 }
272
attributesWithOverride(PropertyDescriptor & other) const273 unsigned int PropertyDescriptor::attributesWithOverride(PropertyDescriptor &other) const
274 {
275 unsigned int mismatch = other.m_attributes ^ m_attributes;
276 unsigned int sharedSeen = other.m_setAttributes & m_setAttributes;
277 unsigned int newAttributes = m_attributes & (DontEnum | DontDelete | ReadOnly);
278
279 if ((sharedSeen & WritableSet) && (mismatch & ReadOnly)) {
280 newAttributes ^= ReadOnly;
281 }
282 if ((sharedSeen & ConfigurableSet) && (mismatch & DontDelete)) {
283 newAttributes ^= DontDelete;
284 }
285 if ((sharedSeen & EnumerableSet) && (mismatch & DontEnum)) {
286 newAttributes ^= DontEnum;
287 }
288
289 return newAttributes;
290 }
291
operator ==(PropertyDescriptor & other) const292 bool PropertyDescriptor::operator==(PropertyDescriptor &other) const
293 {
294 return (m_value == other.value() &&
295 m_setter == other.setter() &&
296 m_getter == other.getter() &&
297 m_attributes == other.m_attributes &&
298 writableSet() == other.writableSet() &&
299 enumerableSet() == other.enumerableSet() &&
300 configureSet() == other.configureSet());
301 }
302
303 }
304
305