Esempio n. 1
0
 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);
     }
 }
Esempio n. 2
0
        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);
        }
Esempio n. 4
0
        /// <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);
        }