FastSetProperty() private method

Sets a property value and attributes, or adds a new property if it doesn't already exist. Any existing attributes are ignored (and not modified).
private FastSetProperty ( object key, object value, PropertyAttributes attributes = PropertyAttributes.Sealed, bool overwriteAttributes = false ) : void
key object The property key (either a string or a Symbol).
value object The intended value of the property.
attributes PropertyAttributes Attributes that indicate whether the property is writable, /// configurable and enumerable.
overwriteAttributes bool Indicates whether to overwrite any existing attributes.
return void
示例#1
0
        public static ObjectInstance Freeze(ObjectInstance obj)
        {
            var properties = new List <PropertyNameAndValue>();

            foreach (var property in obj.Properties)
            {
                properties.Add(property);
            }
            foreach (var property in properties)
            {
                obj.FastSetProperty(property.Key, property.Value,
                                    property.Attributes & ~(PropertyAttributes.NonEnumerable), overwriteAttributes: true);
            }
            obj.IsExtensible = false;
            return(obj);
        }
示例#2
0
        public static ObjectInstance Seal([JSParameter(JSParameterFlags.DoNotConvert)] ObjectInstance obj)
        {
            var properties = new List <PropertyNameAndValue>();

            foreach (var property in obj.Properties)
            {
                properties.Add(property);
            }
            foreach (var property in properties)
            {
                obj.FastSetProperty(property.Name, property.Value,
                                    property.Attributes & ~PropertyAttributes.Configurable, overwriteAttributes: true);
            }
            obj.IsExtensible = false;
            return(obj);
        }
示例#3
0
        //     METHODS
        //_________________________________________________________________________________________


        /// <summary>
        /// Populates the given object with properties, field and methods based on the given .NET
        /// type.
        /// </summary>
        /// <param name="target"> The object to populate. </param>
        /// <param name="type"> The .NET type to search for methods. </param>
        /// <param name="flags"> <c>BindingFlags.Static</c> to populate static methods;
        /// <c>BindingFlags.Instance</c> to populate instance methods. </param>
        internal static void PopulateMembers(ObjectInstance target, Type type, BindingFlags flags)
        {
            // Register static methods as functions.
            var methodGroups = new Dictionary <string, List <MethodBase> >();

            foreach (var member in type.GetMembers(BindingFlags.Public | BindingFlags.DeclaredOnly | flags))
            {
                switch (member.MemberType)
                {
                case MemberTypes.Method:
                    MethodInfo        method = (MethodInfo)member;
                    List <MethodBase> methodGroup;
                    if (methodGroups.TryGetValue(method.Name, out methodGroup) == true)
                    {
                        methodGroup.Add(method);
                    }
                    else
                    {
                        methodGroups.Add(method.Name, new List <MethodBase>()
                        {
                            method
                        });
                    }
                    break;

                case MemberTypes.Property:
                    PropertyInfo property  = (PropertyInfo)member;
                    var          getMethod = property.GetGetMethod();
                    ClrFunction  getter    = getMethod == null ? null : new ClrFunction(target.Engine.Function.InstancePrototype, new ClrBinder(getMethod));
                    var          setMethod = property.GetSetMethod();
                    ClrFunction  setter    = setMethod == null ? null : new ClrFunction(target.Engine.Function.InstancePrototype, new ClrBinder(setMethod));
                    target.DefineProperty(property.Name, new PropertyDescriptor(getter, setter, PropertyAttributes.NonEnumerable), false);

                    // Property getters and setters also show up as methods, so remove them here.
                    // NOTE: only works if properties are enumerated after methods.
                    if (getMethod != null)
                    {
                        methodGroups.Remove(getMethod.Name);
                    }
                    if (setMethod != null)
                    {
                        methodGroups.Remove(setMethod.Name);
                    }
                    break;

                case MemberTypes.Field:
                    FieldInfo   field       = (FieldInfo)member;
                    ClrFunction fieldGetter = new ClrFunction(target.Engine.Function.InstancePrototype, new FieldGetterBinder(field));
                    ClrFunction fieldSetter = new ClrFunction(target.Engine.Function.InstancePrototype, new FieldSetterBinder(field));
                    target.DefineProperty(field.Name, new PropertyDescriptor(fieldGetter, fieldSetter, PropertyAttributes.NonEnumerable), false);
                    break;

                case MemberTypes.Constructor:
                case MemberTypes.NestedType:
                case MemberTypes.Event:
                case MemberTypes.TypeInfo:
                    // Support not yet implemented.
                    break;
                }
            }
            foreach (var methodGroup in methodGroups.Values)
            {
                var binder   = new ClrBinder(methodGroup);
                var function = new ClrFunction(target.Engine.Function.InstancePrototype, binder);
                target.FastSetProperty(binder.Name, function, PropertyAttributes.NonEnumerable, overwriteAttributes: true);
            }
        }
示例#4
0
        //     METHODS
        //_________________________________________________________________________________________


        /// <summary>
        /// Populates the given object with properties, field and methods based on the given .NET
        /// type.
        /// </summary>
        /// <param name="target"> The object to populate. </param>
        /// <param name="type"> The .NET type to search for methods. </param>
        /// <param name="flags"> <c>BindingFlags.Static</c> to populate static methods;
        /// <c>BindingFlags.Instance</c> to populate instance methods. </param>
        internal static void PopulateMembers(ObjectInstance target, Type type, BindingFlags flags)
        {
            // Register static methods as functions.
            var methodGroups = new Dictionary<string, List<MethodBase>>();
            foreach (var member in type.GetMembers(BindingFlags.Public | BindingFlags.DeclaredOnly | flags))
            {
                switch (member.MemberType)
                {
                    case MemberTypes.Method:
                        MethodInfo method = (MethodInfo)member;
                        List<MethodBase> methodGroup;
                        if (methodGroups.TryGetValue(method.Name, out methodGroup) == true)
                            methodGroup.Add(method);
                        else
                            methodGroups.Add(method.Name, new List<MethodBase>() { method });
                        break;

                    case MemberTypes.Property:
                        PropertyInfo property = (PropertyInfo)member;
                        var getMethod = property.GetGetMethod();
                        ClrFunction getter = getMethod == null ? null : new ClrFunction(target.Engine.Function.InstancePrototype, new ClrBinder(getMethod));
                        var setMethod = property.GetSetMethod();
                        ClrFunction setter = setMethod == null ? null : new ClrFunction(target.Engine.Function.InstancePrototype, new ClrBinder(setMethod));
                        target.DefineProperty(property.Name, new PropertyDescriptor(getter, setter, PropertyAttributes.NonEnumerable), false);

                        // Property getters and setters also show up as methods, so remove them here.
                        // NOTE: only works if properties are enumerated after methods.
                        if (getMethod != null)
                            methodGroups.Remove(getMethod.Name);
                        if (setMethod != null)
                            methodGroups.Remove(setMethod.Name);
                        break;
 
                    case MemberTypes.Field:
                        FieldInfo field = (FieldInfo)member;
                        ClrFunction fieldGetter = new ClrFunction(target.Engine.Function.InstancePrototype, new FieldGetterBinder(field));
                        ClrFunction fieldSetter = new ClrFunction(target.Engine.Function.InstancePrototype, new FieldSetterBinder(field));
                        target.DefineProperty(field.Name, new PropertyDescriptor(fieldGetter, fieldSetter, PropertyAttributes.NonEnumerable), false);
                        break;

                    case MemberTypes.Constructor:
                    case MemberTypes.NestedType:
                    case MemberTypes.Event:
                    case MemberTypes.TypeInfo:
                        // Support not yet implemented.
                        break;
                }
                
            }
            foreach (var methodGroup in methodGroups.Values)
            {
                var binder = new ClrBinder(methodGroup);
                var function = new ClrFunction(target.Engine.Function.InstancePrototype, binder);
                target.FastSetProperty(binder.Name, function, PropertyAttributes.NonEnumerable, overwriteAttributes: true);
            }
        }
示例#5
0
        //     INITIALIZATION
        //_________________________________________________________________________________________
        /// <summary>
        /// Creates a new instance of a built-in constructor function.
        /// </summary>
        /// <param name="prototype"> The next object in the prototype chain. </param>
        /// <param name="name"> The name of the function. </param>
        /// <param name="instancePrototype">  </param>
        protected ClrFunction(ObjectInstance prototype, string name, ObjectInstance instancePrototype)
            : base(prototype)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            if (instancePrototype == null)
                throw new ArgumentNullException("instancePrototype");

            // This is a constructor so ignore the "this" parameter when the function is called.
            thisBinding = this;

            // Search through every method in this type looking for [JSFunction] attributes.
            var callBinderMethods = new List<JSBinderMethod>(1);
            var constructBinderMethods = new List<JSBinderMethod>(1);
            var methods = this.GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
            foreach (var method in methods)
            {
                // Search for the [JSCallFunction] and [JSConstructorFunction] attributes.
                var callAttribute = (JSCallFunctionAttribute) Attribute.GetCustomAttribute(method, typeof(JSCallFunctionAttribute));
                var constructorAttribute = (JSConstructorFunctionAttribute)Attribute.GetCustomAttribute(method, typeof(JSConstructorFunctionAttribute));

                // Can't declare both attributes.
                if (callAttribute != null && constructorAttribute != null)
                    throw new InvalidOperationException("Methods cannot be marked with both [JSCallFunction] and [JSConstructorFunction].");

                if (callAttribute != null)
                {
                    // Method is marked with [JSCallFunction]
                    callBinderMethods.Add(new JSBinderMethod(method, callAttribute.Flags));
                }
                else if (constructorAttribute != null)
                {
                    var binderMethod = new JSBinderMethod(method, constructorAttribute.Flags);
                    constructBinderMethods.Add(binderMethod);

                    // Constructors must return ObjectInstance or a derived type.
                    if (typeof(ObjectInstance).IsAssignableFrom(binderMethod.ReturnType) == false)
                        throw new InvalidOperationException(string.Format("Constructors must return {0} (or a derived type).", typeof(ObjectInstance).Name));
                }
            }

            // Initialize the Call function.
            if (callBinderMethods.Count > 0)
                this.callBinder = new JSBinder(callBinderMethods);
            else
                this.callBinder = new JSBinder(new JSBinderMethod(new Func<object>(() => Undefined.Value).Method));

            // Initialize the Construct function.
            if (constructBinderMethods.Count > 0)
                this.constructBinder = new JSBinder(constructBinderMethods);
            else
                this.constructBinder = new JSBinder(new JSBinderMethod(new Func<ObjectInstance>(() => this.Engine.Object.Construct()).Method));

            // Add function properties.
            this.FastSetProperty("name", name);
            this.FastSetProperty("length", this.callBinder.FunctionLength);
            this.FastSetProperty("prototype", instancePrototype);
            instancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable);
        }
示例#6
0
        //     INITIALIZATION
        //_________________________________________________________________________________________

        /// <summary>
        /// Creates a new instance of a built-in constructor function.
        /// </summary>
        /// <param name="prototype"> The next object in the prototype chain. </param>
        /// <param name="name"> The name of the function. </param>
        /// <param name="instancePrototype">  </param>
        protected ClrFunction(ObjectInstance prototype, string name, ObjectInstance instancePrototype)
            : base(prototype)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }
            if (instancePrototype == null)
            {
                throw new ArgumentNullException("instancePrototype");
            }

            // This is a constructor so ignore the "this" parameter when the function is called.
            thisBinding = this;

            // Search through every method in this type looking for [JSFunction] attributes.
            var callBinderMethods      = new List <JSBinderMethod>(1);
            var constructBinderMethods = new List <JSBinderMethod>(1);
            var methods = this.GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);

            foreach (var method in methods)
            {
                // Search for the [JSCallFunction] and [JSConstructorFunction] attributes.
                var callAttribute        = (JSCallFunctionAttribute)Attribute.GetCustomAttribute(method, typeof(JSCallFunctionAttribute));
                var constructorAttribute = (JSConstructorFunctionAttribute)Attribute.GetCustomAttribute(method, typeof(JSConstructorFunctionAttribute));

                // Can't declare both attributes.
                if (callAttribute != null && constructorAttribute != null)
                {
                    throw new InvalidOperationException("Methods cannot be marked with both [JSCallFunction] and [JSConstructorFunction].");
                }

                if (callAttribute != null)
                {
                    // Method is marked with [JSCallFunction]
                    callBinderMethods.Add(new JSBinderMethod(method, callAttribute.Flags));
                }
                else if (constructorAttribute != null)
                {
                    var binderMethod = new JSBinderMethod(method, constructorAttribute.Flags);
                    constructBinderMethods.Add(binderMethod);

                    // Constructors must return ObjectInstance or a derived type.
                    if (typeof(ObjectInstance).IsAssignableFrom(binderMethod.ReturnType) == false)
                    {
                        throw new InvalidOperationException(string.Format("Constructors must return {0} (or a derived type).", typeof(ObjectInstance).Name));
                    }
                }
            }

            // Initialize the Call function.
            if (callBinderMethods.Count > 0)
            {
                this.callBinder = new JSBinder(callBinderMethods);
            }
            else
            {
                this.callBinder = new JSBinder(new JSBinderMethod(new Func <object>(() => Undefined.Value).Method));
            }

            // Initialize the Construct function.
            if (constructBinderMethods.Count > 0)
            {
                this.constructBinder = new JSBinder(constructBinderMethods);
            }
            else
            {
                this.constructBinder = new JSBinder(new JSBinderMethod(new Func <ObjectInstance>(() => this.Engine.Object.Construct()).Method));
            }

            // Add function properties.
            this.FastSetProperty("name", name);
            this.FastSetProperty("length", this.callBinder.FunctionLength);
            this.FastSetProperty("prototype", instancePrototype);
            instancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable);
        }
示例#7
0
 public static ObjectInstance Seal(ObjectInstance obj)
 {
     var properties = new List<PropertyNameAndValue>();
     foreach (var property in obj.Properties)
         properties.Add(property);
     foreach (var property in properties)
     {
         obj.FastSetProperty(property.Key, property.Value,
             property.Attributes & ~PropertyAttributes.Configurable, overwriteAttributes: true);
     }
     obj.IsExtensible = false;
     return obj;
 }