/// <summary> /// Creates or alters the named own property to /// have the state described by a Property /// Descriptor. The flag controls failure handling. /// </summary> /// <param name="propertyName"></param> /// <param name="desc"></param> /// <param name="throwOnError"></param> /// <returns></returns> public virtual bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError) { var current = GetOwnProperty(propertyName); if (current == desc) { return true; } if (current == PropertyDescriptor.Undefined) { if (!Extensible) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } else { if (desc.IsGenericDescriptor() || desc.IsDataDescriptor()) { SetOwnProperty(propertyName, new PropertyDescriptor(desc) { Value = desc.Value.HasValue ? desc.Value : JsValue.Undefined, Writable = desc.Writable.HasValue ? desc.Writable.Value : false, Enumerable = desc.Enumerable.HasValue ? desc.Enumerable.Value : false, Configurable = desc.Configurable.HasValue ? desc.Configurable.Value : false }); } else { SetOwnProperty(propertyName, new PropertyDescriptor(desc) { Get = desc.Get, Set = desc.Set, Enumerable = desc.Enumerable.HasValue ? desc.Enumerable : false, Configurable = desc.Configurable.HasValue ? desc.Configurable : false, }); } } return true; } // Step 5 if (!current.Configurable.HasValue && !current.Enumerable.HasValue && !current.Writable.HasValue && !current.Get.HasValue && !current.Set.HasValue && !current.Value.HasValue) { return true; } // Step 6 if ( current.Configurable == desc.Configurable && current.Writable == desc.Writable && current.Enumerable == desc.Enumerable && ((!current.Get.HasValue && !desc.Get.HasValue) || (current.Get.HasValue && desc.Get.HasValue && ExpressionInterpreter.SameValue(current.Get.Value, desc.Get.Value))) && ((!current.Set.HasValue && !desc.Set.HasValue) || (current.Set.HasValue && desc.Set.HasValue && ExpressionInterpreter.SameValue(current.Set.Value, desc.Set.Value))) && ((!current.Value.HasValue && !desc.Value.HasValue) || (current.Value.HasValue && desc.Value.HasValue && ExpressionInterpreter.StrictlyEqual(current.Value.Value, desc.Value.Value))) ) { return true; } if (!current.Configurable.HasValue || !current.Configurable.Value) { if (desc.Configurable.HasValue && desc.Configurable.Value) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } if (desc.Enumerable.HasValue && (!current.Enumerable.HasValue || desc.Enumerable.Value != current.Enumerable.Value)) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } } if (!desc.IsGenericDescriptor()) { if (current.IsDataDescriptor() != desc.IsDataDescriptor()) { if (!current.Configurable.HasValue || !current.Configurable.Value) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } if (current.IsDataDescriptor()) { SetOwnProperty(propertyName, current = new PropertyDescriptor( get: Undefined.Instance, set: Undefined.Instance, enumerable: current.Enumerable, configurable: current.Configurable )); } else { SetOwnProperty(propertyName, current = new PropertyDescriptor( value: Undefined.Instance, writable: null, enumerable: current.Enumerable, configurable: current.Configurable )); } } else if (current.IsDataDescriptor() && desc.IsDataDescriptor()) { if (!current.Configurable.HasValue || current.Configurable.Value == false) { if (!current.Writable.HasValue || !current.Writable.Value && desc.Writable.HasValue && desc.Writable.Value) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } if (!current.Writable.Value) { if (desc.Value.HasValue && !ExpressionInterpreter.SameValue(desc.Value.Value, current.Value.Value)) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } } } } else if (current.IsAccessorDescriptor() && desc.IsAccessorDescriptor()) { if (!current.Configurable.HasValue || !current.Configurable.Value) { if ((desc.Set.HasValue && !ExpressionInterpreter.SameValue(desc.Set.Value, current.Set.HasValue ? current.Set.Value : Undefined.Instance)) || (desc.Get.HasValue && !ExpressionInterpreter.SameValue(desc.Get.Value, current.Get.HasValue ? current.Get.Value : Undefined.Instance))) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } } } } if (desc.Value.HasValue) { current.Value = desc.Value; } if (desc.Writable.HasValue) { current.Writable = desc.Writable; } if (desc.Enumerable.HasValue) { current.Enumerable = desc.Enumerable; } if (desc.Configurable.HasValue) { current.Configurable = desc.Configurable; } if (desc.Get.HasValue) { current.Get = desc.Get; } if (desc.Set.HasValue) { current.Set = desc.Set; } return true; }
/// <summary> /// Creates or alters the named own property to /// have the state described by a Property /// Descriptor. The flag controls failure handling. /// </summary> /// <param name="propertyName"></param> /// <param name="desc"></param> /// <param name="throwOnError"></param> /// <returns></returns> public virtual bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError) { var current = GetOwnProperty(propertyName); if (current == PropertyDescriptor.Undefined) { if (!Extensible) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } else { if (desc.IsGenericDescriptor() || desc.IsDataDescriptor()) { Properties[propertyName] = new PropertyDescriptor(desc) { Value = desc.Value.HasValue ? desc.Value : JsValue.Undefined, Writable = desc.Writable.HasValue ? desc.Writable : false }; } else { Properties[propertyName] = new PropertyDescriptor(desc) { Enumerable = desc.Enumerable.HasValue ? desc.Enumerable : false, Configurable = desc.Configurable.HasValue ? desc.Configurable : false, }; } } return true; } // Step 5 if (!current.Configurable.HasValue && !current.Enumerable.HasValue && !current.Writable.HasValue && !current.Get.HasValue && !current.Set.HasValue && !current.Value.HasValue) { return true; } // Step 6 var configurableIsSame = current.Configurable.HasValue ? desc.Configurable.HasValue && (current.Configurable.Value == desc.Configurable.Value) : !desc.Configurable.HasValue; var enumerableIsSame = current.Enumerable.HasValue ? desc.Enumerable.HasValue && (current.Enumerable.Value == desc.Enumerable.Value) : !desc.Enumerable.HasValue; var writableIsSame = true; var valueIsSame = true; if (current.IsDataDescriptor() && desc.IsDataDescriptor()) { var currentDataDescriptor = current; var descDataDescriptor = desc; writableIsSame = currentDataDescriptor.Writable.HasValue ? descDataDescriptor.Writable.HasValue && (currentDataDescriptor.Writable.Value == descDataDescriptor.Writable.Value) : !descDataDescriptor.Writable.HasValue; var valueA = currentDataDescriptor.Value.HasValue ? currentDataDescriptor.Value.Value : Undefined.Instance; var valueB = descDataDescriptor.Value.HasValue ? descDataDescriptor.Value.Value : Undefined.Instance; valueIsSame = ExpressionInterpreter.SameValue(valueA, valueB); } else if (current.IsAccessorDescriptor() && desc.IsAccessorDescriptor()) { var currentAccessorDescriptor = current; var descAccessorDescriptor = desc; var getValueA = currentAccessorDescriptor.Get.HasValue ? currentAccessorDescriptor.Get.Value : Undefined.Instance; var getValueB = descAccessorDescriptor.Get.HasValue ? descAccessorDescriptor.Get.Value : Undefined.Instance; var setValueA = currentAccessorDescriptor.Set.HasValue ? currentAccessorDescriptor.Set.Value : Undefined.Instance; var setValueB = descAccessorDescriptor.Set.HasValue ? descAccessorDescriptor.Set.Value : Undefined.Instance; valueIsSame = ExpressionInterpreter.SameValue(getValueA, getValueB) && ExpressionInterpreter.SameValue(setValueA, setValueB); } else { valueIsSame = false; } if (configurableIsSame && enumerableIsSame && writableIsSame && valueIsSame) { return true; } if (!current.Configurable.HasValue || !current.Configurable.Value.AsBoolean()) { if (desc.Configurable.HasValue && desc.Configurable.Value.AsBoolean()) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } if (desc.Enumerable.HasValue && (!current.Enumerable.HasValue || desc.Enumerable.Value != current.Enumerable.Value)) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } } if (!desc.IsGenericDescriptor()) { if (current.IsDataDescriptor() != desc.IsDataDescriptor()) { if (!current.Configurable.HasValue || !current.Configurable.Value.AsBoolean()) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } if (current.IsDataDescriptor()) { Properties[propertyName] = current = new PropertyDescriptor( get: Undefined.Instance, set: Undefined.Instance, enumerable: current.Enumerable.HasValue && current.Enumerable.Value.AsBoolean(), configurable: current.Configurable.HasValue && current.Configurable.Value.AsBoolean() ); } else { Properties[propertyName] = current = new PropertyDescriptor( value: Undefined.Instance, writable: null, enumerable: current.Enumerable.HasValue && current.Enumerable.Value.AsBoolean(), configurable: current.Configurable.HasValue && current.Configurable.Value.AsBoolean() ); } } else if (current.IsDataDescriptor() && desc.IsDataDescriptor()) { if (!current.Configurable.HasValue || current.Configurable.Value.AsBoolean() == false) { if (!current.Writable.HasValue || !current.Writable.Value.AsBoolean() && desc.Writable.HasValue && desc.Writable.Value.AsBoolean()) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } if (!current.Writable.Value.AsBoolean()) { if (desc.Value.HasValue && !valueIsSame) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } } } } else if (current.IsAccessorDescriptor() && desc.IsAccessorDescriptor()) { if (!current.Configurable.HasValue || !current.Configurable.Value.AsBoolean()) { if ((desc.Set.HasValue && !ExpressionInterpreter.SameValue(desc.Set.Value, current.Set.HasValue ? current.Set.Value : Undefined.Instance)) || (desc.Get.HasValue && !ExpressionInterpreter.SameValue(desc.Get.Value, current.Get.HasValue ? current.Get.Value : Undefined.Instance))) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return false; } } } } if (desc.Value.HasValue) { current.Value = desc.Value; } if (desc.Writable.HasValue) { current.Writable = desc.Writable; } if (desc.Enumerable.HasValue) { current.Enumerable = desc.Enumerable; } if (desc.Configurable.HasValue) { current.Configurable = desc.Configurable; } if (desc.Get.HasValue) { current.Get = desc.Get; } if (desc.Set.HasValue) { current.Set = desc.Set; } return true; }