public ObjectWrapper(Engine engine, object obj) : base(engine) { Target = obj; _typeDescriptor = TypeDescriptor.Get(obj.GetType()); if (_typeDescriptor.LengthProperty is not null) { // create a forwarder to produce length from Count or Length if one of them is present var functionInstance = new ClrFunctionInstance(engine, "length", GetLength); var descriptor = new GetSetPropertyDescriptor(functionInstance, Undefined, PropertyFlag.Configurable); SetProperty(KnownKeys.Length, descriptor); } }
public ObjectWrapper(Engine engine, object obj) : base(engine) { Target = obj; var type = obj.GetType(); if (ObjectIsArrayLikeClrCollection(type)) { // create a forwarder to produce length from Count or Length if one of them is present var lengthProperty = type.GetProperty("Count") ?? type.GetProperty("Length"); if (lengthProperty is null) { return; } IsArrayLike = true; var functionInstance = new ClrFunctionInstance(engine, "length", (thisObj, arguments) => JsNumber.Create((int)lengthProperty.GetValue(obj))); var descriptor = new GetSetPropertyDescriptor(functionInstance, Undefined, PropertyFlag.Configurable); SetProperty(KnownKeys.Length, descriptor); } }
private object BuildObjectNormal() { var obj = _engine.Object.Construct(_properties.Length); bool isStrictModeCode = _engine._isStrict || StrictModeScope.IsStrictModeCode; for (var i = 0; i < _properties.Length; i++) { var objectProperty = _properties[i]; if (objectProperty is null) { // spread if (_valueExpressions[i].GetValue() is ObjectInstance source) { source.CopyDataProperties(obj, null); } continue; } var property = objectProperty._value; var propName = objectProperty.KeyJsString ?? property.GetKey(_engine); PropertyDescriptor propDesc; if (property.Kind == PropertyKind.Init || property.Kind == PropertyKind.Data) { var expr = _valueExpressions[i]; var propValue = expr.GetValue().Clone(); if (expr._expression.IsFunctionWithName()) { var functionInstance = (FunctionInstance)propValue; functionInstance.SetFunctionName(propName); } propDesc = new PropertyDescriptor(propValue, PropertyFlag.ConfigurableEnumerableWritable); } else if (property.Kind == PropertyKind.Get || property.Kind == PropertyKind.Set) { var function = property.Value as IFunction ?? ExceptionHelper.ThrowSyntaxError <IFunction>(_engine); var functionInstance = new ScriptFunctionInstance( _engine, function, _engine.ExecutionContext.LexicalEnvironment, isStrictModeCode ); functionInstance.SetFunctionName(propName); functionInstance._prototypeDescriptor = null; propDesc = new GetSetPropertyDescriptor( get: property.Kind == PropertyKind.Get ? functionInstance : null, set: property.Kind == PropertyKind.Set ? functionInstance : null, PropertyFlag.Enumerable | PropertyFlag.Configurable); } else { return(ExceptionHelper.ThrowArgumentOutOfRangeException <object>()); } obj.DefineOwnProperty(propName, propDesc); } return(obj); }
/// <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); } var descValue = desc.Value; if (current == PropertyDescriptor.Undefined) { if (!Extensible) { if (throwOnError) { ExceptionHelper.ThrowTypeError(Engine); } return(false); } else { if (desc.IsGenericDescriptor() || desc.IsDataDescriptor()) { PropertyDescriptor propertyDescriptor; if ((desc._flags & PropertyFlag.ConfigurableEnumerableWritable) == PropertyFlag.ConfigurableEnumerableWritable) { propertyDescriptor = new PropertyDescriptor(descValue ?? Undefined, PropertyFlag.ConfigurableEnumerableWritable); } else if ((desc._flags & PropertyFlag.ConfigurableEnumerableWritable) == 0) { propertyDescriptor = new PropertyDescriptor(descValue ?? Undefined, PropertyFlag.AllForbidden); } else { propertyDescriptor = new PropertyDescriptor(desc) { Value = descValue ?? Undefined }; } SetOwnProperty(propertyName, propertyDescriptor); } else { SetOwnProperty(propertyName, new GetSetPropertyDescriptor(desc)); } } return(true); } // Step 5 var currentGet = current.Get; var currentSet = current.Set; var currentValue = current.Value; if ((current._flags & PropertyFlag.ConfigurableSet | PropertyFlag.EnumerableSet | PropertyFlag.WritableSet) == 0 && ReferenceEquals(currentGet, null) && ReferenceEquals(currentSet, null) && ReferenceEquals(currentValue, null)) { return(true); } // Step 6 var descGet = desc.Get; var descSet = desc.Set; if ( current.Configurable == desc.Configurable && current.ConfigurableSet == desc.ConfigurableSet && current.Writable == desc.Writable && current.WritableSet == desc.WritableSet && current.Enumerable == desc.Enumerable && current.EnumerableSet == desc.EnumerableSet && ((ReferenceEquals(currentGet, null) && ReferenceEquals(descGet, null)) || (!ReferenceEquals(currentGet, null) && !ReferenceEquals(descGet, null) && ExpressionInterpreter.SameValue(currentGet, descGet))) && ((ReferenceEquals(currentSet, null) && ReferenceEquals(descSet, null)) || (!ReferenceEquals(currentSet, null) && !ReferenceEquals(descSet, null) && ExpressionInterpreter.SameValue(currentSet, descSet))) && ((ReferenceEquals(currentValue, null) && ReferenceEquals(descValue, null)) || (!ReferenceEquals(currentValue, null) && !ReferenceEquals(descValue, null) && ExpressionInterpreter.StrictlyEqual(currentValue, descValue))) ) { return(true); } if (!current.Configurable) { if (desc.Configurable) { if (throwOnError) { ExceptionHelper.ThrowTypeError(Engine); } return(false); } if (desc.EnumerableSet && (desc.Enumerable != current.Enumerable)) { if (throwOnError) { ExceptionHelper.ThrowTypeError(Engine); } return(false); } } if (!desc.IsGenericDescriptor()) { if (current.IsDataDescriptor() != desc.IsDataDescriptor()) { if (!current.Configurable) { if (throwOnError) { ExceptionHelper.ThrowTypeError(Engine); } return(false); } if (current.IsDataDescriptor()) { var flags = current.Flags & ~(PropertyFlag.Writable | PropertyFlag.WritableSet); SetOwnProperty(propertyName, current = new GetSetPropertyDescriptor( get: JsValue.Undefined, set: JsValue.Undefined, flags: flags )); } else { var flags = current.Flags & ~(PropertyFlag.Writable | PropertyFlag.WritableSet); SetOwnProperty(propertyName, current = new PropertyDescriptor( value: JsValue.Undefined, flags: flags )); } } else if (current.IsDataDescriptor() && desc.IsDataDescriptor()) { if (!current.Configurable) { if (!current.Writable && desc.Writable) { if (throwOnError) { ExceptionHelper.ThrowTypeError(Engine); } return(false); } if (!current.Writable) { if (!ReferenceEquals(descValue, null) && !ExpressionInterpreter.SameValue(descValue, currentValue)) { if (throwOnError) { ExceptionHelper.ThrowTypeError(Engine); } return(false); } } } } else if (current.IsAccessorDescriptor() && desc.IsAccessorDescriptor()) { if (!current.Configurable) { if ((!ReferenceEquals(descSet, null) && !ExpressionInterpreter.SameValue(descSet, currentSet ?? Undefined)) || (!ReferenceEquals(descGet, null) && !ExpressionInterpreter.SameValue(descGet, currentGet ?? Undefined))) { if (throwOnError) { ExceptionHelper.ThrowTypeError(Engine); } return(false); } } } } if (!ReferenceEquals(descValue, null)) { current.Value = descValue; } if (desc.WritableSet) { current.Writable = desc.Writable; } if (desc.EnumerableSet) { current.Enumerable = desc.Enumerable; } if (desc.ConfigurableSet) { current.Configurable = desc.Configurable; } PropertyDescriptor mutable = null; if (!ReferenceEquals(descGet, null)) { mutable = new GetSetPropertyDescriptor(mutable ?? current); ((GetSetPropertyDescriptor)mutable).SetGet(descGet); } if (!ReferenceEquals(descSet, null)) { mutable = new GetSetPropertyDescriptor(mutable ?? current); ((GetSetPropertyDescriptor)mutable).SetSet(descSet); } if (mutable != null) { // replace old with new type that supports get and set FastSetProperty(propertyName, mutable); } return(true); }