public PropertyDescriptor(PropertyDescriptor descriptor) { Get = descriptor.Get; Set = descriptor.Set; Value = descriptor.Value; Enumerable = descriptor.Enumerable; Configurable = descriptor.Configurable; Writable = descriptor.Writable; }
public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError, "Can't define a property of a NamespaceReference"); } return false; }
/// <summary> /// Optimized version of [[Put]] when the property is known to be already declared /// </summary> /// <param name="name"></param> /// <param name="value"></param> public void FastSetProperty(string name, PropertyDescriptor value) { Properties[name] = value; }
/// <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; }
/// <summary> /// Sets the specified named property to the value /// of the second parameter. The flag controls /// failure handling. /// </summary> /// <param name="propertyName"></param> /// <param name="value"></param> /// <param name="throwOnError"></param> public virtual void Put(string propertyName, JsValue value, bool throwOnError) { if (!CanPut(propertyName)) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } return; } var ownDesc = GetOwnProperty(propertyName); if (ownDesc.IsDataDescriptor()) { var valueDesc = new PropertyDescriptor(value: value, writable: null, enumerable:null, configurable:null); DefineOwnProperty(propertyName, valueDesc, throwOnError); return; } // property is an accessor or inherited var desc = GetProperty(propertyName); if (desc.IsAccessorDescriptor()) { var setter = desc.Set.Value.TryCast<ICallable>(); setter.Call(new JsValue(this), new [] {value}); } else { var newDesc = new PropertyDescriptor(value, true, true, true); DefineOwnProperty(propertyName, newDesc, throwOnError); } }
public static JsValue FromPropertyDescriptor(Engine engine, PropertyDescriptor desc) { if (desc == Undefined) { return Native.Undefined.Instance; } var obj = engine.Object.Construct(Arguments.Empty); if (desc.IsDataDescriptor()) { obj.DefineOwnProperty("value", new PropertyDescriptor(value: desc.Value.HasValue ? desc.Value.Value : Native.Undefined.Instance, writable: true, enumerable: true, configurable: true ), false); obj.DefineOwnProperty("writable", new PropertyDescriptor(value: desc.Writable.HasValue && desc.Writable.Value.AsBoolean(), writable: true, enumerable: true, configurable: true), false); } else { obj.DefineOwnProperty("get", new PropertyDescriptor(desc.Get ?? Native.Undefined.Instance, writable: true, enumerable: true, configurable: true ), false); obj.DefineOwnProperty("set", new PropertyDescriptor(desc.Set ?? Native.Undefined.Instance, writable: true, enumerable: true, configurable: true), false); } obj.DefineOwnProperty("enumerable", new PropertyDescriptor(value: desc.Enumerable.HasValue && desc.Enumerable.Value.AsBoolean(), writable: true, enumerable: true, configurable: true), false); obj.DefineOwnProperty("configurable", new PropertyDescriptor(value: desc.Configurable.HasValue && desc.Configurable.Value.AsBoolean(), writable: true, enumerable: true, configurable: true), false); return obj; }
public static PropertyDescriptor ToPropertyDescriptor(Engine engine, JsValue o) { var obj = o.TryCast<ObjectInstance>(); if (obj == null) { throw new JavaScriptException(engine.TypeError); } if ((obj.HasProperty("value") || obj.HasProperty("writable")) && (obj.HasProperty("get") || obj.HasProperty("set"))) { throw new JavaScriptException(engine.TypeError); } var desc = new PropertyDescriptor(); if (obj.HasProperty("enumerable")) { desc.Enumerable = TypeConverter.ToBoolean(obj.Get("enumerable")); } if (obj.HasProperty("configurable")) { desc.Configurable = TypeConverter.ToBoolean(obj.Get("configurable")); } if (obj.HasProperty("value")) { var value = obj.Get("value"); desc.Value = value; } if (obj.HasProperty("writable")) { desc.Writable = TypeConverter.ToBoolean(obj.Get("writable")); } if (obj.HasProperty("get")) { var getter = obj.Get("get"); if (getter != JsValue.Undefined && getter.TryCast<ICallable>() == null) { throw new JavaScriptException(engine.TypeError); } desc.Get = getter; } if (obj.HasProperty("set")) { var setter = obj.Get("set"); if (setter != Native.Undefined.Instance && setter.TryCast<ICallable>() == null) { throw new JavaScriptException(engine.TypeError); } desc.Set = setter; } if (desc.Get.HasValue || desc.Get.HasValue) { if (desc.Value.HasValue || desc.Writable.HasValue) { throw new JavaScriptException(engine.TypeError); } } return desc; }
public JsValue EvaluateObjectExpression(ObjectExpression objectExpression) { // http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.5 var obj = _engine.Object.Construct(Arguments.Empty); foreach (var property in objectExpression.Properties) { var propName = property.Key.GetKey(); var previous = obj.GetOwnProperty(propName); PropertyDescriptor propDesc; switch (property.Kind) { case PropertyKind.Data: var exprValue = _engine.EvaluateExpression(property.Value); var propValue = _engine.GetValue(exprValue); propDesc = new PropertyDescriptor(propValue, true, true, true); break; case PropertyKind.Get: var getter = property.Value as FunctionExpression; if (getter == null) { throw new JavaScriptException(_engine.SyntaxError); } ScriptFunctionInstance get; using (new StrictModeScope(getter.Strict)) { get = new ScriptFunctionInstance( _engine, getter, _engine.ExecutionContext.LexicalEnvironment, StrictModeScope.IsStrictModeCode ); } propDesc = new PropertyDescriptor(get: get, set: null, enumerable: true, configurable:true); break; case PropertyKind.Set: var setter = property.Value as FunctionExpression; if (setter == null) { throw new JavaScriptException(_engine.SyntaxError); } ScriptFunctionInstance set; using (new StrictModeScope(setter.Strict)) { set = new ScriptFunctionInstance( _engine, setter, _engine.ExecutionContext.LexicalEnvironment, StrictModeScope.IsStrictModeCode ); } propDesc = new PropertyDescriptor(get:null, set: set, enumerable: true, configurable: true); break; default: throw new ArgumentOutOfRangeException(); } if (previous != PropertyDescriptor.Undefined) { if (StrictModeScope.IsStrictModeCode && previous.IsDataDescriptor() && propDesc.IsDataDescriptor()) { throw new JavaScriptException(_engine.SyntaxError); } if (previous.IsDataDescriptor() && propDesc.IsAccessorDescriptor()) { throw new JavaScriptException(_engine.SyntaxError); } if (previous.IsAccessorDescriptor() && propDesc.IsDataDescriptor()) { throw new JavaScriptException(_engine.SyntaxError); } if (previous.IsAccessorDescriptor() && propDesc.IsAccessorDescriptor()) { if (propDesc.Set.HasValue && previous.Set.HasValue) { throw new JavaScriptException(_engine.SyntaxError); } if (propDesc.Get.HasValue && previous.Get.HasValue) { throw new JavaScriptException(_engine.SyntaxError); } } } obj.DefineOwnProperty(propName, propDesc, false); } return obj; }
public static PropertyDescriptor ToPropertyDescriptor(Engine engine, JsValue o) { var obj = o.TryCast <ObjectInstance>(); if (obj == null) { throw new JavaScriptException(engine.TypeError); } if ((obj.HasProperty("value") || obj.HasProperty("writable")) && (obj.HasProperty("get") || obj.HasProperty("set"))) { throw new JavaScriptException(engine.TypeError); } var desc = new PropertyDescriptor(); if (obj.HasProperty("enumerable")) { desc.Enumerable = TypeConverter.ToBoolean(obj.Get("enumerable")); } if (obj.HasProperty("configurable")) { desc.Configurable = TypeConverter.ToBoolean(obj.Get("configurable")); } if (obj.HasProperty("value")) { var value = obj.Get("value"); desc.Value = value; } if (obj.HasProperty("writable")) { desc.Writable = TypeConverter.ToBoolean(obj.Get("writable")); } if (obj.HasProperty("get")) { var getter = obj.Get("get"); if (getter != JsValue.Undefined && getter.TryCast <ICallable>() == null) { throw new JavaScriptException(engine.TypeError); } desc.Get = getter; } if (obj.HasProperty("set")) { var setter = obj.Get("set"); if (setter != Native.Undefined.Instance && setter.TryCast <ICallable>() == null) { throw new JavaScriptException(engine.TypeError); } desc.Set = setter; } if (desc.Get.HasValue || desc.Get.HasValue) { if (desc.Value.HasValue || desc.Writable.HasValue) { throw new JavaScriptException(engine.TypeError); } } return(desc); }
public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError) { var oldLenDesc = GetOwnProperty("length"); var oldLen = TypeConverter.ToNumber(oldLenDesc.Value.Value); if (propertyName == "length") { if (!desc.Value.HasValue) { return base.DefineOwnProperty("length", desc, throwOnError); } var newLenDesc = new PropertyDescriptor(desc); uint newLen = TypeConverter.ToUint32(desc.Value.Value); if (newLen != TypeConverter.ToNumber(desc.Value.Value)) { throw new JavaScriptException(_engine.RangeError); } newLenDesc.Value = newLen; if (newLen >= oldLen) { return base.DefineOwnProperty("length", newLenDesc, throwOnError); } if (!oldLenDesc.Writable.Value.AsBoolean()) { if (throwOnError) { throw new JavaScriptException(_engine.TypeError); } return false; } bool newWritable; if (!newLenDesc.Writable.HasValue || newLenDesc.Writable.Value.AsBoolean()) { newWritable = true; } else { newWritable = false; newLenDesc.Writable = true; } var succeeded = base.DefineOwnProperty("length", newLenDesc, throwOnError); if (!succeeded) { return false; } // in the case of sparse arrays, treat each concrete element instead of // iterating over all indexes if (Properties.Count < oldLen - newLen) { var keys = Properties.Keys.ToArray(); foreach (var key in keys) { uint index; // is it the index of the array if (uint.TryParse(key, out index) && index >= newLen && index < oldLen) { var deleteSucceeded = Delete(key, false); if (!deleteSucceeded) { newLenDesc.Value = new JsValue(index + 1); if (!newWritable) { newLenDesc.Writable = JsValue.False; } base.DefineOwnProperty("length", newLenDesc, false); if (throwOnError) { throw new JavaScriptException(_engine.TypeError); } return false; } } } } else { while (newLen < oldLen) { // algorithm as per the spec oldLen--; var deleteSucceeded = Delete(TypeConverter.ToString(oldLen), false); if (!deleteSucceeded) { newLenDesc.Value = oldLen + 1; if (!newWritable) { newLenDesc.Writable = false; } base.DefineOwnProperty("length", newLenDesc, false); if (throwOnError) { throw new JavaScriptException(_engine.TypeError); } return false; } } } if (!newWritable) { DefineOwnProperty("length", new PropertyDescriptor(value: null, writable: false, enumerable: null, configurable: null), false); } return true; } else if (IsArrayIndex(propertyName)) { var index = TypeConverter.ToUint32(propertyName); if (index >= oldLen && !oldLenDesc.Writable.Value.AsBoolean()) { if (throwOnError) { throw new JavaScriptException(_engine.TypeError); } return false; } var succeeded = base.DefineOwnProperty(propertyName, desc, false); if (!succeeded) { if (throwOnError) { throw new JavaScriptException(_engine.TypeError); } return false; } if (index >= oldLen) { oldLenDesc.Value = index + 1; base.DefineOwnProperty("length", oldLenDesc, false); } return true; } return base.DefineOwnProperty(propertyName, desc, throwOnError); }
public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError) { if (!Strict && ParameterMap != null) { var map = ParameterMap; var isMapped = map.GetOwnProperty(propertyName); var allowed = base.DefineOwnProperty(propertyName, desc, false); if (!allowed) { if (throwOnError) { throw new JavaScriptException(Engine.TypeError); } } if (isMapped != PropertyDescriptor.Undefined) { if (desc.IsAccessorDescriptor()) { map.Delete(propertyName, false); } else { if (desc.Value.HasValue && desc.Value.Value != Undefined.Instance) { map.Put(propertyName, desc.Value.Value, throwOnError); } if (desc.Writable.HasValue && desc.Writable.Value == false) { map.Delete(propertyName, false); } } } return true; } return base.DefineOwnProperty(propertyName, desc, throwOnError); }