// 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("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.Sealed, false); this.FastSetProperty("length", Math.Max(targetFunction.Length - boundArguments.Length, 0), PropertyAttributes.Sealed, false); this.FastSetProperty("prototype", this.Engine.Object.Construct(), PropertyAttributes.Writable, false); this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable, false); // 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, true); this.FastSetProperty("arguments", accessor, PropertyAttributes.IsAccessorProperty, 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, "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"])) { 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"])) { 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) { attributes |= PropertyAttributes.Configurable; } if (writable) { attributes |= PropertyAttributes.Writable; } if (enumerable) { attributes |= PropertyAttributes.Enumerable; } // Either a value or an accessor is possible. object descriptorValue = value; if (isAccessor) { descriptorValue = new PropertyAccessorValue(getter, setter); } // Create the new property descriptor. return(new PropertyDescriptor(descriptorValue, attributes)); }