1/*
2 This file is part of the KDE libraries
3 Copyright (C) 2012 Bernd Buschinski <b.buschinski@googlemail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program 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
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18*/
19
20
21#include "propertydescriptor.h"
22#include "object.h"
23#include "operations.h"
24
25#include <stdio.h>
26
27namespace KJS {
28
29PropertyDescriptor::PropertyDescriptor()
30 : m_attributes(DontEnum|DontDelete|ReadOnly),
31 m_setAttributes(0),
32 m_value(0),
33 m_getter(0),
34 m_setter(0)
35{
36}
37
38//ECMAScript Edition 5.1r6 - 8.10.1
39bool PropertyDescriptor::isAccessorDescriptor() const
40{
41 return (m_getter || m_setter);
42}
43
44//ECMAScript Edition 5.1r6 - 8.10.2
45bool PropertyDescriptor::isDataDescriptor() const
46{
47 if (!m_value && !(writableSet()))
48 return false;
49 return true;
50}
51
52//ECMAScript Edition 5.1r6 - 8.10.3
53bool PropertyDescriptor::isGenericDescriptor() const
54{
55 return (!isAccessorDescriptor() && !isDataDescriptor());
56}
57
58//ECMAScript Edition 5.1r6 - 8.10.4 - FromPropertyDescriptor
59JSObject* 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
78bool PropertyDescriptor::setPropertyDescriptorFromObject(ExecState *exec, JSValue* jsValue)
79{
80 JSObject *obj = jsValue->getObject();
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(obj->get(exec, exec->propertyNames().enumerable)->toBoolean(exec));
88
89 if (obj->hasProperty(exec, exec->propertyNames().configurable))
90 setConfigureable(obj->get(exec, exec->propertyNames().configurable)->toBoolean(exec));
91
92 if (obj->hasProperty(exec, exec->propertyNames().value))
93 setValue(obj->get(exec, exec->propertyNames().value));
94
95 if (obj->hasProperty(exec, exec->propertyNames().writable))
96 setWritable(obj->get(exec, exec->propertyNames().writable)->toBoolean(exec));
97
98 if (obj->hasProperty(exec, exec->propertyNames().get)) {
99 JSValue* getter = obj->get(exec, exec->propertyNames().get);
100 if (!getter->isUndefined()) {
101 if (!getter->implementsCall()) {
102 throwError(exec, TypeError, "Getter: \'" + getter->toString(exec) + "\' is not Callable");
103 return false;
104 }
105 }
106 setGetter(getter);
107 }
108
109 if (obj->hasProperty(exec, exec->propertyNames().set)) {
110 JSValue* setter = obj->get(exec, exec->propertyNames().set);
111 if (!setter->isUndefined()) {
112 if (!setter->implementsCall()) {
113 throwError(exec, TypeError, "Setter: \'" + setter->toString(exec) + "\' is not Callable");
114 return false;
115 }
116 }
117 setSetter(setter);
118 }
119
120 if (getter() || setter()) {
121 if (value() || writableSet()) {
122 throwError(exec, TypeError, "can not mix accessor descriptor and data descriptor");
123 return false;
124 }
125 }
126 return true;
127}
128
129bool PropertyDescriptor::setPropertyDescriptorValues(ExecState*, JSValue* value, unsigned int attributes)
130{
131 setEnumerable(!(attributes & DontEnum));
132 setConfigureable(!(attributes & DontDelete));
133
134 if (!value)
135 return false;
136 if (value->isUndefined() || value->type() != GetterSetterType) {
137 setValue(value);
138 setWritable(!(attributes & ReadOnly));
139 } else {
140 GetterSetterImp *gs = static_cast<GetterSetterImp *>(value);
141 setGetter(gs->getGetter() ? gs->getGetter() : jsUndefined());
142 setSetter(gs->getSetter() ? gs->getSetter() : jsUndefined());
143 }
144 return true;
145}
146
147bool PropertyDescriptor::configurable() const
148{
149 return !(m_attributes & DontDelete);
150}
151
152bool PropertyDescriptor::enumerable() const
153{
154 return !(m_attributes & DontEnum);
155}
156
157bool PropertyDescriptor::writable() const
158{
159 return !(m_attributes & ReadOnly);
160}
161
162bool PropertyDescriptor::configureSet() const
163{
164 return m_setAttributes & ConfigurableSet;
165}
166
167bool PropertyDescriptor::enumerableSet() const
168{
169 return m_setAttributes & EnumerableSet;
170}
171
172bool PropertyDescriptor::writableSet() const
173{
174 return m_setAttributes & WritableSet;
175}
176
177JSValue* PropertyDescriptor::getter() const
178{
179 return m_getter;
180}
181
182JSValue* PropertyDescriptor::setter() const
183{
184 return m_setter;
185}
186
187JSValue* PropertyDescriptor::value() const
188{
189 return m_value;
190}
191
192void PropertyDescriptor::setEnumerable(bool enumerable)
193{
194 if (enumerable)
195 m_attributes &= ~DontEnum;
196 else
197 m_attributes |= DontEnum;
198 m_setAttributes |= EnumerableSet;
199}
200
201void PropertyDescriptor::setConfigureable(bool configureable)
202{
203 if (configureable)
204 m_attributes &= ~DontDelete;
205 else
206 m_attributes |= DontDelete;
207 m_setAttributes |= ConfigurableSet;
208}
209
210void PropertyDescriptor::setValue(JSValue* value)
211{
212 m_value = value;
213}
214
215void PropertyDescriptor::setWritable(bool writable)
216{
217 if (writable)
218 m_attributes &= ~ReadOnly;
219 else
220 m_attributes |= ReadOnly;
221 m_setAttributes |= WritableSet;
222}
223
224void PropertyDescriptor::setGetter(JSValue* getter)
225{
226 m_getter = getter;
227 m_attributes &= ~ReadOnly;
228}
229
230void PropertyDescriptor::setSetter(JSValue* setter)
231{
232 m_setter = setter;
233 m_attributes &= ~ReadOnly;
234}
235
236unsigned int PropertyDescriptor::attributes() const
237{
238 return m_attributes;
239}
240
241bool PropertyDescriptor::isEmpty() const
242{
243 return !m_setAttributes && !m_getter && !m_setter && !m_value;
244}
245
246inline bool compareValue(ExecState* exec, JSValue* a, JSValue* b)
247{
248 return (a == b || (a && b && sameValue(exec, a, b)));
249}
250
251// different from compareValue, if "own" getter/setter is missing (is 0) we are still the same
252inline bool compareFunction(ExecState* exec, JSValue* a, JSValue* b)
253{
254 return (a == b || (b != 0 && a == 0) || (a && b && sameValue(exec, a, b)));
255}
256
257bool PropertyDescriptor::equalTo(ExecState* exec, PropertyDescriptor& other) const
258{
259 return (compareValue(exec, m_value, other.value()) &&
260 compareFunction(exec, m_getter, other.getter()) &&
261 compareFunction(exec, m_setter, other.setter()) &&
262 attributes() == other.attributes());
263}
264
265unsigned int PropertyDescriptor::attributesWithOverride(PropertyDescriptor& other) const
266{
267 unsigned int mismatch = other.m_attributes ^ m_attributes;
268 unsigned int sharedSeen = other.m_setAttributes & m_setAttributes;
269 unsigned int newAttributes = m_attributes & (DontEnum|DontDelete|ReadOnly);
270
271 if ((sharedSeen & WritableSet) && (mismatch & ReadOnly))
272 newAttributes ^= ReadOnly;
273 if ((sharedSeen & ConfigurableSet) && (mismatch & DontDelete))
274 newAttributes ^= DontDelete;
275 if ((sharedSeen & EnumerableSet) && (mismatch & DontEnum))
276 newAttributes ^= DontEnum;
277
278 return newAttributes;
279}
280
281bool PropertyDescriptor::operator==(PropertyDescriptor& other) const
282{
283 return (m_value == other.value() &&
284 m_setter == other.setter() &&
285 m_getter == other.getter() &&
286 m_attributes == other.m_attributes &&
287 writableSet() == other.writableSet() &&
288 enumerableSet() == other.enumerableSet() &&
289 configureSet() == other.configureSet());
290}
291
292}
293
294