File indexing completed on 2024-05-12 15:43:33
0001 /* 0002 This file is part of the KDE libraries 0003 Copyright 2012 Bernd Buschinski <b.buschinski@googlemail.com> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Lesser General Public 0007 License as published by the Free Software Foundation; either 0008 version 2.1 of the License, or (at your option) any later version. 0009 0010 This library is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Lesser General Public License for more details. 0014 0015 You should have received a copy of the GNU Lesser General Public 0016 License along with this library. If not, see <http://www.gnu.org/licenses/>. 0017 */ 0018 0019 #include "propertydescriptor.h" 0020 #include "object.h" 0021 #include "operations.h" 0022 0023 #include <stdio.h> 0024 0025 namespace KJS 0026 { 0027 0028 PropertyDescriptor::PropertyDescriptor() 0029 : m_attributes(DontEnum | DontDelete | ReadOnly), 0030 m_setAttributes(0), 0031 m_value(nullptr), 0032 m_getter(nullptr), 0033 m_setter(nullptr) 0034 { 0035 } 0036 0037 //ECMAScript Edition 5.1r6 - 8.10.1 0038 bool PropertyDescriptor::isAccessorDescriptor() const 0039 { 0040 return (m_getter || m_setter); 0041 } 0042 0043 //ECMAScript Edition 5.1r6 - 8.10.2 0044 bool PropertyDescriptor::isDataDescriptor() const 0045 { 0046 if (!m_value && !(writableSet())) { 0047 return false; 0048 } 0049 return true; 0050 } 0051 0052 //ECMAScript Edition 5.1r6 - 8.10.3 0053 bool PropertyDescriptor::isGenericDescriptor() const 0054 { 0055 return (!isAccessorDescriptor() && !isDataDescriptor()); 0056 } 0057 0058 //ECMAScript Edition 5.1r6 - 8.10.4 - FromPropertyDescriptor 0059 JSObject *PropertyDescriptor::fromPropertyDescriptor(ExecState *exec) 0060 { 0061 JSObject *ret = new JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()); 0062 0063 if (isDataDescriptor()) { 0064 ret->put(exec, exec->propertyNames().writable, jsBoolean(writable())); 0065 ret->put(exec, exec->propertyNames().value, value() ? value() : jsUndefined()); 0066 } else { 0067 ret->put(exec, exec->propertyNames().get, getter() ? getter() : jsUndefined()); 0068 ret->put(exec, exec->propertyNames().set, setter() ? setter() : jsUndefined()); 0069 } 0070 0071 ret->put(exec, exec->propertyNames().enumerable, jsBoolean(enumerable())); 0072 ret->put(exec, exec->propertyNames().configurable, jsBoolean(configurable())); 0073 0074 return ret; 0075 } 0076 0077 //ECMAScript Edition 5.1r6 - 8.10.5 - ToPropertyDescriptor 0078 bool PropertyDescriptor::setPropertyDescriptorFromObject(ExecState *exec, JSValue *jsValue) 0079 { 0080 JSObject *obj = JSValue::getObject(jsValue); 0081 if (!obj) { 0082 throwError(exec, TypeError, "not an Object"); 0083 return false; 0084 } 0085 0086 if (obj->hasProperty(exec, exec->propertyNames().enumerable)) { 0087 setEnumerable(JSValue::toBoolean(obj->get(exec, exec->propertyNames().enumerable), exec)); 0088 } 0089 0090 if (obj->hasProperty(exec, exec->propertyNames().configurable)) { 0091 setConfigureable(JSValue::toBoolean(obj->get(exec, exec->propertyNames().configurable), exec)); 0092 } 0093 0094 if (obj->hasProperty(exec, exec->propertyNames().value)) { 0095 setValue(obj->get(exec, exec->propertyNames().value)); 0096 } 0097 0098 if (obj->hasProperty(exec, exec->propertyNames().writable)) { 0099 setWritable(JSValue::toBoolean(obj->get(exec, exec->propertyNames().writable), exec)); 0100 } 0101 0102 if (obj->hasProperty(exec, exec->propertyNames().get)) { 0103 JSValue *getter = obj->get(exec, exec->propertyNames().get); 0104 if (!JSValue::isUndefined(getter)) { 0105 if (!JSValue::implementsCall(getter)) { 0106 throwError(exec, TypeError, "Getter: \'" + JSValue::toString(getter, exec) + "\' is not Callable"); 0107 return false; 0108 } 0109 } 0110 setGetter(getter); 0111 } 0112 0113 if (obj->hasProperty(exec, exec->propertyNames().set)) { 0114 JSValue *setter = obj->get(exec, exec->propertyNames().set); 0115 if (!JSValue::isUndefined(setter)) { 0116 if (!JSValue::implementsCall(setter)) { 0117 throwError(exec, TypeError, "Setter: \'" + JSValue::toString(setter, exec) + "\' is not Callable"); 0118 return false; 0119 } 0120 } 0121 setSetter(setter); 0122 } 0123 0124 if (getter() || setter()) { 0125 if (value() || writableSet()) { 0126 throwError(exec, TypeError, "can not mix accessor descriptor and data descriptor"); 0127 return false; 0128 } 0129 } 0130 return true; 0131 } 0132 0133 bool PropertyDescriptor::setPropertyDescriptorValues(ExecState *, JSValue *value, unsigned int attributes) 0134 { 0135 setEnumerable(!(attributes & DontEnum)); 0136 setConfigureable(!(attributes & DontDelete)); 0137 0138 if (!value) { 0139 return false; 0140 } 0141 if (JSValue::isUndefined(value) || JSValue::type(value) != GetterSetterType) { 0142 setValue(value); 0143 setWritable(!(attributes & ReadOnly)); 0144 } else { 0145 GetterSetterImp *gs = static_cast<GetterSetterImp *>(value); 0146 setGetter(gs->getGetter() ? gs->getGetter() : jsUndefined()); 0147 setSetter(gs->getSetter() ? gs->getSetter() : jsUndefined()); 0148 } 0149 return true; 0150 } 0151 0152 bool PropertyDescriptor::configurable() const 0153 { 0154 return !(m_attributes & DontDelete); 0155 } 0156 0157 bool PropertyDescriptor::enumerable() const 0158 { 0159 return !(m_attributes & DontEnum); 0160 } 0161 0162 bool PropertyDescriptor::writable() const 0163 { 0164 return !(m_attributes & ReadOnly); 0165 } 0166 0167 bool PropertyDescriptor::configureSet() const 0168 { 0169 return m_setAttributes & ConfigurableSet; 0170 } 0171 0172 bool PropertyDescriptor::enumerableSet() const 0173 { 0174 return m_setAttributes & EnumerableSet; 0175 } 0176 0177 bool PropertyDescriptor::writableSet() const 0178 { 0179 return m_setAttributes & WritableSet; 0180 } 0181 0182 JSValue *PropertyDescriptor::getter() const 0183 { 0184 return m_getter; 0185 } 0186 0187 JSValue *PropertyDescriptor::setter() const 0188 { 0189 return m_setter; 0190 } 0191 0192 JSValue *PropertyDescriptor::value() const 0193 { 0194 return m_value; 0195 } 0196 0197 void PropertyDescriptor::setEnumerable(bool enumerable) 0198 { 0199 if (enumerable) { 0200 m_attributes &= ~DontEnum; 0201 } else { 0202 m_attributes |= DontEnum; 0203 } 0204 m_setAttributes |= EnumerableSet; 0205 } 0206 0207 void PropertyDescriptor::setConfigureable(bool configurable) 0208 { 0209 if (configurable) { 0210 m_attributes &= ~DontDelete; 0211 } else { 0212 m_attributes |= DontDelete; 0213 } 0214 m_setAttributes |= ConfigurableSet; 0215 } 0216 0217 void PropertyDescriptor::setValue(JSValue *value) 0218 { 0219 m_value = value; 0220 } 0221 0222 void PropertyDescriptor::setWritable(bool writable) 0223 { 0224 if (writable) { 0225 m_attributes &= ~ReadOnly; 0226 } else { 0227 m_attributes |= ReadOnly; 0228 } 0229 m_setAttributes |= WritableSet; 0230 } 0231 0232 void PropertyDescriptor::setGetter(JSValue *getter) 0233 { 0234 m_getter = getter; 0235 m_attributes &= ~ReadOnly; 0236 } 0237 0238 void PropertyDescriptor::setSetter(JSValue *setter) 0239 { 0240 m_setter = setter; 0241 m_attributes &= ~ReadOnly; 0242 } 0243 0244 unsigned int PropertyDescriptor::attributes() const 0245 { 0246 return m_attributes; 0247 } 0248 0249 bool PropertyDescriptor::isEmpty() const 0250 { 0251 return !m_setAttributes && !m_getter && !m_setter && !m_value; 0252 } 0253 0254 inline bool compareValue(ExecState *exec, JSValue *a, JSValue *b) 0255 { 0256 return (a == b || (a && b && sameValue(exec, a, b))); 0257 } 0258 0259 // different from compareValue, if "own" getter/setter is missing (is 0) we are still the same 0260 inline bool compareFunction(ExecState *exec, JSValue *a, JSValue *b) 0261 { 0262 return (a == b || (b != nullptr && a == nullptr) || (a && b && sameValue(exec, a, b))); 0263 } 0264 0265 bool PropertyDescriptor::equalTo(ExecState *exec, PropertyDescriptor &other) const 0266 { 0267 return (compareValue(exec, m_value, other.value()) && 0268 compareFunction(exec, m_getter, other.getter()) && 0269 compareFunction(exec, m_setter, other.setter()) && 0270 attributes() == other.attributes()); 0271 } 0272 0273 unsigned int PropertyDescriptor::attributesWithOverride(PropertyDescriptor &other) const 0274 { 0275 unsigned int mismatch = other.m_attributes ^ m_attributes; 0276 unsigned int sharedSeen = other.m_setAttributes & m_setAttributes; 0277 unsigned int newAttributes = m_attributes & (DontEnum | DontDelete | ReadOnly); 0278 0279 if ((sharedSeen & WritableSet) && (mismatch & ReadOnly)) { 0280 newAttributes ^= ReadOnly; 0281 } 0282 if ((sharedSeen & ConfigurableSet) && (mismatch & DontDelete)) { 0283 newAttributes ^= DontDelete; 0284 } 0285 if ((sharedSeen & EnumerableSet) && (mismatch & DontEnum)) { 0286 newAttributes ^= DontEnum; 0287 } 0288 0289 return newAttributes; 0290 } 0291 0292 bool PropertyDescriptor::operator==(PropertyDescriptor &other) const 0293 { 0294 return (m_value == other.value() && 0295 m_setter == other.setter() && 0296 m_getter == other.getter() && 0297 m_attributes == other.m_attributes && 0298 writableSet() == other.writableSet() && 0299 enumerableSet() == other.enumerableSet() && 0300 configureSet() == other.configureSet()); 0301 } 0302 0303 } 0304