// 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 [JSCallFunction] and [JSConstructorFunction] 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); }