Represents a the value of an accessor property.
        //     INITIALIZATION
        //_________________________________________________________________________________________

        /// <summary>
        /// Creates a new instance of a user-defined function.
        /// </summary>
        /// <param name="targetFunction"> The function that was bound. </param>
        /// <param name="boundThis"> The value of the "this" parameter when the target function is called. </param>
        /// <param name="boundArguments"> Zero or more bound argument values. </param>
        internal BoundFunction(FunctionInstance targetFunction, object boundThis, object[] boundArguments)
            : base(targetFunction.Prototype)
        {
            if (targetFunction == null)
            {
                throw new ArgumentNullException(nameof(targetFunction));
            }
            if (boundArguments == null)
            {
                boundArguments = new object[0];
            }
            this.TargetFunction = targetFunction;
            this.BoundThis      = boundThis;
            this.BoundArguments = boundArguments;

            // Add function properties.
            this.FastSetProperty("name", targetFunction.Name, PropertyAttributes.Configurable);
            this.FastSetProperty("length", Math.Max(targetFunction.Length - boundArguments.Length, 0), PropertyAttributes.Configurable);
            this.FastSetProperty("prototype", this.Engine.Object.Construct(), PropertyAttributes.Writable);
            this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable);

            // Caller and arguments cannot be accessed.
            var thrower  = new ThrowTypeErrorFunction(this.Engine.Function, "The 'caller' or 'arguments' properties cannot be accessed on a bound function.");
            var accessor = new PropertyAccessorValue(thrower, thrower);

            this.FastSetProperty("caller", accessor, PropertyAttributes.IsAccessorProperty, overwriteAttributes: true);
            this.FastSetProperty("arguments", accessor, PropertyAttributes.IsAccessorProperty, overwriteAttributes: true);
        }
        //     INITIALIZATION
        //_________________________________________________________________________________________

        /// <summary>
        /// Creates a new instance of a user-defined function.
        /// </summary>
        /// <param name="prototype"> The next object in the prototype chain. </param>
        /// <param name="targetFunction"> The function that was bound. </param>
        /// <param name="boundThis"> The value of the "this" parameter when the target function is called. </param>
        /// <param name="boundArguments"> Zero or more bound argument values. </param>
        internal BoundFunction(FunctionInstance targetFunction, object boundThis, object[] boundArguments)
            : base(targetFunction.Prototype)
        {
            if (targetFunction == null)
                throw new ArgumentNullException("targetFunction");
            if (boundArguments == null)
                boundArguments = new object[0];
            this.TargetFunction = targetFunction;
            this.BoundThis = boundThis;
            this.BoundArguments = boundArguments;

            // Add function properties.
            this.FastSetProperty("name", targetFunction.Name);
            this.FastSetProperty("length", Math.Max(targetFunction.Length - boundArguments.Length, 0));
            this.FastSetProperty("prototype", this.Engine.Object.Construct(), PropertyAttributes.Writable);
            this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable);
            
            // Caller and arguments cannot be accessed.
            var thrower = new ThrowTypeErrorFunction(this.Engine.Function, "The 'caller' or 'arguments' properties cannot be accessed on a bound function.");
            var accessor = new PropertyAccessorValue(thrower, thrower);
            this.FastSetProperty("caller", accessor, PropertyAttributes.IsAccessorProperty, overwriteAttributes: true);
            this.FastSetProperty("arguments", accessor, PropertyAttributes.IsAccessorProperty, overwriteAttributes: true);
        }
        //     OBJECT SERIALIZATION AND DESERIALIZATION
        //_________________________________________________________________________________________

        /// <summary>
        /// Creates a property descriptor from an object containing any of the following
        /// properties: configurable, writable, enumerable, value, get, set.
        /// </summary>
        /// <param name="obj"> The object to get the property values from. </param>
        /// <param name="defaults"> The values to use if the relevant value is not specified. </param>
        /// <returns> A PropertyDescriptor that corresponds to the object. </returns>
        public static PropertyDescriptor FromObject(ObjectInstance obj, PropertyDescriptor defaults)
        {
            if (obj == null)
            {
                return(PropertyDescriptor.Undefined);
            }

            // Read configurable attribute.
            bool configurable = defaults.IsConfigurable;

            if (obj.HasProperty("configurable"))
            {
                configurable = TypeConverter.ToBoolean(obj["configurable"]);
            }

            // Read writable attribute.
            bool writable = defaults.IsWritable;

            if (obj.HasProperty("writable"))
            {
                writable = TypeConverter.ToBoolean(obj["writable"]);
            }

            // Read enumerable attribute.
            bool enumerable = defaults.IsEnumerable;

            if (obj.HasProperty("enumerable"))
            {
                enumerable = TypeConverter.ToBoolean(obj["enumerable"]);
            }

            // Read property value.
            object value = defaults.Value;

            if (obj.HasProperty("value"))
            {
                value = obj["value"];
            }

            // The descriptor is an accessor if get or set is present.
            bool isAccessor = false;

            // Read get accessor.
            FunctionInstance getter = defaults.Getter;

            if (obj.HasProperty("get"))
            {
                if (obj.HasProperty("value"))
                {
                    throw new JavaScriptException(obj.Engine, ErrorType.TypeError, "Property descriptors cannot have both 'get' and 'value' set");
                }
                if (obj.HasProperty("writable"))
                {
                    throw new JavaScriptException(obj.Engine, ErrorType.TypeError, "Property descriptors with 'get' or 'set' defined must not have 'writable' set");
                }
                if (obj["get"] is FunctionInstance)
                {
                    getter = (FunctionInstance)obj["get"];
                }
                else if (TypeUtilities.IsUndefined(obj["get"]) == true)
                {
                    getter = null;
                }
                else
                {
                    throw new JavaScriptException(obj.Engine, ErrorType.TypeError, "Property descriptor 'get' must be a function");
                }
                isAccessor = true;
            }

            // Read set accessor.
            FunctionInstance setter = defaults.Setter;

            if (obj.HasProperty("set"))
            {
                if (obj.HasProperty("value"))
                {
                    throw new JavaScriptException(obj.Engine, ErrorType.TypeError, "Property descriptors cannot have both 'set' and 'value' set");
                }
                if (obj.HasProperty("writable"))
                {
                    throw new JavaScriptException(obj.Engine, ErrorType.TypeError, "Property descriptors with 'get' or 'set' defined must not have 'writable' set");
                }
                if (obj["set"] is FunctionInstance)
                {
                    setter = (FunctionInstance)obj["set"];
                }
                else if (TypeUtilities.IsUndefined(obj["set"]) == true)
                {
                    setter = null;
                }
                else
                {
                    throw new JavaScriptException(obj.Engine, ErrorType.TypeError, "Property descriptor 'set' must be a function");
                }
                isAccessor = true;
            }

            // Build up the attributes enum.
            PropertyAttributes attributes = PropertyAttributes.Sealed;

            if (configurable == true)
            {
                attributes |= PropertyAttributes.Configurable;
            }
            if (writable == true)
            {
                attributes |= PropertyAttributes.Writable;
            }
            if (enumerable == true)
            {
                attributes |= PropertyAttributes.Enumerable;
            }

            // Either a value or an accessor is possible.
            object descriptorValue = value;

            if (isAccessor == true)
            {
                descriptorValue = new PropertyAccessorValue(getter, setter);
            }

            // Create the new property descriptor.
            return(new PropertyDescriptor(descriptorValue, attributes));
        }
        //     OBJECT SERIALIZATION AND DESERIALIZATION
        //_________________________________________________________________________________________

        /// <summary>
        /// Creates a property descriptor from an object containing any of the following
        /// properties: configurable, writable, enumerable, value, get, set.
        /// </summary>
        /// <param name="obj"> The object to get the property values from. </param>
        /// <param name="defaults"> The values to use if the relevant value is not specified. </param>
        /// <returns> A PropertyDescriptor that corresponds to the object. </returns>
        public static PropertyDescriptor FromObject(ObjectInstance obj, PropertyDescriptor defaults)
        {
            if (obj == null)
                return PropertyDescriptor.Undefined;

            // Read configurable attribute.
            bool configurable = defaults.IsConfigurable;
            if (obj.HasProperty("configurable"))
                configurable = TypeConverter.ToBoolean(obj["configurable"]);

            // Read writable attribute.
            bool writable = defaults.IsWritable;
            if (obj.HasProperty("writable"))
                writable = TypeConverter.ToBoolean(obj["writable"]);

            // Read enumerable attribute.
            bool enumerable = defaults.IsEnumerable;
            if (obj.HasProperty("enumerable"))
                enumerable = TypeConverter.ToBoolean(obj["enumerable"]);

            // Read property value.
            object value = defaults.Value;
            if (obj.HasProperty("value"))
                value = obj["value"];

            // The descriptor is an accessor if get or set is present.
            bool isAccessor = false;

            // Read get accessor.
            FunctionInstance getter = defaults.Getter;
            if (obj.HasProperty("get"))
            {
                if (obj.HasProperty("value"))
                    throw new JavaScriptException(obj.Engine, "TypeError", "Property descriptors cannot have both 'get' and 'value' set");
                if (obj.HasProperty("writable"))
                    throw new JavaScriptException(obj.Engine, "TypeError", "Property descriptors with 'get' or 'set' defined must not have 'writable' set");
                if (obj["get"] is FunctionInstance)
                    getter = (FunctionInstance)obj["get"];
                else if (TypeUtilities.IsUndefined(obj["get"]) == true)
                    getter = null;
                else
                    throw new JavaScriptException(obj.Engine, "TypeError", "Property descriptor 'get' must be a function");
                isAccessor = true;
            }

            // Read set accessor.
            FunctionInstance setter = defaults.Setter;
            if (obj.HasProperty("set"))
            {
                if (obj.HasProperty("value"))
                    throw new JavaScriptException(obj.Engine, "TypeError", "Property descriptors cannot have both 'set' and 'value' set");
                if (obj.HasProperty("writable"))
                    throw new JavaScriptException(obj.Engine, "TypeError", "Property descriptors with 'get' or 'set' defined must not have 'writable' set");
                if (obj["set"] is FunctionInstance)
                    setter = (FunctionInstance)obj["set"];
                else if (TypeUtilities.IsUndefined(obj["set"]) == true)
                    setter = null;
                else
                    throw new JavaScriptException(obj.Engine, "TypeError", "Property descriptor 'set' must be a function");
                isAccessor = true;
            }

            // Build up the attributes enum.
            PropertyAttributes attributes = PropertyAttributes.Sealed;
            if (configurable == true)
                attributes |= PropertyAttributes.Configurable;
            if (writable == true)
                attributes |= PropertyAttributes.Writable;
            if (enumerable == true)
                attributes |= PropertyAttributes.Enumerable;

            // Either a value or an accessor is possible.
            object descriptorValue = value;
            if (isAccessor == true)
                descriptorValue = new PropertyAccessorValue(getter, setter);

            // Create the new property descriptor.
            return new PropertyDescriptor(descriptorValue, attributes);
        }