private static void UpdatePropertyDescriptor(JSObject O, string P, JSObject desc) { JSValue tmp; JSValue value = JSUndefined.Instance; JSFunctionBase getter = null; JSFunctionBase setter = null; bool enumerable = true; bool configurable = true; bool writable = true; bool hasValue = false; bool hasGet = false; bool hasSet = false; bool hasEnumerable = false; bool hasConfigurable = false; bool hasWritable = false; if (desc.TryGetPropertyValue("enumerable", out tmp)) { enumerable = tmp.BoolValue(); hasEnumerable = true; } if (desc.TryGetPropertyValue("configurable", out tmp)) { configurable = tmp.BoolValue(); hasConfigurable = true; } if (desc.TryGetPropertyValue("value", out tmp)) { value = tmp; hasValue = true; } if (desc.TryGetPropertyValue("writable", out tmp)) { writable = tmp.BoolValue(); hasWritable = true; } if (desc.TryGetPropertyValue("get", out tmp)) { if (tmp is JSUndefined) { getter = null; } else { if (!(tmp is JSFunctionBase)) { throw new JSRuntimeException("TypeError", "invalid 'get' property in property descriptor"); } getter = (JSFunctionBase)tmp; } hasGet = true; } if (desc.TryGetPropertyValue("set", out tmp)) { if (tmp is JSUndefined) { setter = null; } else { if (!(tmp is JSFunctionBase)) { throw new JSRuntimeException("TypeError", "invalid 'set' property in property descriptor"); } setter = (JSFunctionBase)tmp; } hasSet = true; } if (hasValue || hasGet || hasSet || hasEnumerable || hasConfigurable || hasWritable) { PropWrapper newProp; bool bIsAccessor; if (!(hasGet || hasSet)) { bIsAccessor = false; } else { if (hasValue || hasWritable) { throw new JSRuntimeException("TypeError", "property descriptor contained values for both data and accessor"); } bIsAccessor = true; } PropWrapper oldProp = O.GetOwnPropertyRef(P); if (oldProp == null) { if (!O.IsExtensible) { throw new JSRuntimeException("TypeError", "object is not extensible"); } if (bIsAccessor) { newProp = new AccessorProperty(getter, setter, writable, enumerable, configurable); } else { newProp = new DataProperty(value, writable, enumerable, configurable); } } else { if (oldProp is DataProperty) { DataProperty _o = oldProp as DataProperty; if ((((!hasValue || JSValue.JSEqualsExact(value, _o.Value)) && (!hasEnumerable || (writable == oldProp.Writable))) && (!hasConfigurable || (enumerable == oldProp.Enumerable))) && (!hasWritable || (configurable == oldProp.Configurable))) { return; } } else if (oldProp is AccessorProperty) { AccessorProperty _o = oldProp as AccessorProperty; if ((((!hasEnumerable || (writable == oldProp.Writable)) && (!hasConfigurable || (enumerable == oldProp.Enumerable))) && (!hasGet || (getter == _o.Getter))) && (!hasSet || (setter == _o.Setter))) { return; } } if (!oldProp.Configurable) { throw new JSRuntimeException("TypeError", "property is not configurable"); } if ((bIsAccessor && (oldProp is AccessorProperty)) || (!bIsAccessor && (oldProp is DataProperty))) { newProp = oldProp; } else if (bIsAccessor) { newProp = new AccessorProperty(getter, setter); } else { newProp = new DataProperty(value); } if (hasConfigurable) { newProp.Configurable = configurable; } if (hasEnumerable) { newProp.Enumerable = enumerable; } if (bIsAccessor) { if (hasGet) { ((AccessorProperty)newProp).Getter = getter; } if (hasSet) { ((AccessorProperty)newProp).Setter = setter; } } else { if (hasWritable) { ((DataProperty)newProp).Value = value; } if (hasValue) { newProp.Set(O, value); } } } O.SetProp(P, newProp); } }