// 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); }
/// <summary> /// Creates a new instance of a function which calls the given binder. /// </summary> /// <param name="prototype"> The next object in the prototype chain. </param> /// <param name="binder"> An object representing a collection of methods to bind to. </param> internal ClrFunction(ObjectInstance prototype, Binder binder) : base(prototype) { m_callBinder = binder; // Add function properties. FastSetProperty("name", binder.Name, PropertyAttributes.Sealed, false); FastSetProperty("length", binder.FunctionLength, PropertyAttributes.Sealed, false); //this.FastSetProperty("prototype", this.Engine.Object.Construct()); //this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable); }
/// <summary> /// Creates a new instance of a function which calls one or more provided methods. /// </summary> /// <param name="prototype"> The next object in the prototype chain. </param> /// <param name="methods"> An enumerable collection of methods that logically comprise a /// single method group. </param> /// <param name="name"> The name of the function. Pass <c>null</c> to use the name of the /// provided methods for the function name (in this case all the provided methods must have /// the same name). </param> /// <param name="length"> The "typical" number of arguments expected by the function. Pass /// <c>-1</c> to use the maximum of arguments expected by any of the provided methods. </param> internal ClrFunction(ObjectInstance prototype, IEnumerable <JSBinderMethod> methods, string name, int length) : base(prototype) { m_callBinder = new JSBinder(methods); // Add function properties. FastSetProperty("name", name ?? m_callBinder.Name, PropertyAttributes.Sealed, false); FastSetProperty("length", length >= 0 ? length : m_callBinder.FunctionLength, PropertyAttributes.Sealed, false); //this.FastSetProperty("prototype", this.Engine.Object.Construct()); //this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable); }
/// <summary> /// Creates a new instance of a function which calls the given binder. /// </summary> /// <param name="prototype"> The next object in the prototype chain. </param> /// <param name="binder"> An object representing a collection of methods to bind to. </param> internal ClrFunction(ObjectInstance prototype, Binder binder) : base(prototype) { this.callBinder = binder; // Add function properties. this.FastSetProperty("name", binder.Name); this.FastSetProperty("length", binder.FunctionLength); //this.FastSetProperty("prototype", this.Engine.Object.Construct()); //this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable); }
/// <summary> /// Creates a new instance of a function which calls one or more provided methods. /// </summary> /// <param name="prototype"> The next object in the prototype chain. </param> /// <param name="methods"> An enumerable collection of methods that logically comprise a /// single method group. </param> /// <param name="name"> The name of the function. Pass <c>null</c> to use the name of the /// provided methods for the function name (in this case all the provided methods must have /// the same name). </param> /// <param name="length"> The "typical" number of arguments expected by the function. Pass /// <c>-1</c> to use the maximum of arguments expected by any of the provided methods. </param> internal ClrFunction(ObjectInstance prototype, IEnumerable<JSBinderMethod> methods, string name = null, int length = -1) : base(prototype) { this.callBinder = new JSBinder(methods); // Add function properties. this.FastSetProperty("name", name == null ? this.callBinder.Name : name); this.FastSetProperty("length", length >= 0 ? length : this.callBinder.FunctionLength); //this.FastSetProperty("prototype", this.Engine.Object.Construct()); //this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable); }
/// <summary> /// Creates a new instance of a function which calls one or more provided methods. /// </summary> /// <param name="prototype"> The next object in the prototype chain. </param> /// <param name="methods"> An enumerable collection of methods that logically comprise a /// single method group. </param> /// <param name="name"> The name of the function. Pass <c>null</c> to use the name of the /// provided methods for the function name (in this case all the provided methods must have /// the same name). </param> /// <param name="length"> The "typical" number of arguments expected by the function. Pass /// <c>-1</c> to use the maximum of arguments expected by any of the provided methods. </param> internal ClrFunction(ObjectInstance prototype, IEnumerable <JSBinderMethod> methods, string name = null, int length = -1) : base(prototype) { this.callBinder = new JSBinder(methods); // Add function properties. this.FastSetProperty("name", name == null ? this.callBinder.Name : name); this.FastSetProperty("length", length >= 0 ? length : this.callBinder.FunctionLength); //this.FastSetProperty("prototype", this.Engine.Object.Construct()); //this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable); }
/// <summary> /// Creates a new instance of a function which calls the given delegate. /// </summary> /// <param name="prototype"> The next object in the prototype chain. </param> /// <param name="delegateToCall"> The delegate to call. </param> /// <param name="name"> The name of the function. Pass <c>null</c> to use the name of the /// delegate for the function name. </param> /// <param name="length"> The "typical" number of arguments expected by the function. Pass /// <c>-1</c> to use the number of arguments expected by the delegate. </param> internal ClrFunction(ObjectInstance prototype, Delegate delegateToCall, string name, int length) : base(prototype) { // Initialize the [[Call]] method. m_callBinder = new JSBinder(new JSBinderMethod(delegateToCall.Method, JSFunctionFlags.None)); // If the delegate has a class instance, use that to call the method. m_thisBinding = delegateToCall.Target; // Add function properties. FastSetProperty("name", name ?? m_callBinder.Name, PropertyAttributes.Sealed, false); FastSetProperty("length", length >= 0 ? length : m_callBinder.FunctionLength, PropertyAttributes.Sealed, false); //this.FastSetProperty("prototype", this.Engine.Object.Construct()); //this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable); }
/// <summary> /// Creates a new instance of a function which calls the given delegate. /// </summary> /// <param name="prototype"> The next object in the prototype chain. </param> /// <param name="delegateToCall"> The delegate to call. </param> /// <param name="name"> The name of the function. Pass <c>null</c> to use the name of the /// delegate for the function name. </param> /// <param name="length"> The "typical" number of arguments expected by the function. Pass /// <c>-1</c> to use the number of arguments expected by the delegate. </param> internal ClrFunction(ObjectInstance prototype, Delegate delegateToCall, string name = null, int length = -1) : base(prototype) { // Initialize the [[Call]] method. this.callBinder = new JSBinder(new JSBinderMethod(delegateToCall.Method)); // If the delegate has a class instance, use that to call the method. this.thisBinding = delegateToCall.Target; // Add function properties. this.FastSetProperty("name", name != null ? name : this.callBinder.Name); this.FastSetProperty("length", length >= 0 ? length : this.callBinder.FunctionLength); //this.FastSetProperty("prototype", this.Engine.Object.Construct()); //this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable); }
/// <summary> /// Creates a new instance of a function which calls the given delegate. /// </summary> /// <param name="prototype"> The next object in the prototype chain. </param> /// <param name="delegateToCall"> The delegate to call. </param> /// <param name="name"> The name of the function. Pass <c>null</c> to use the name of the /// delegate for the function name. </param> /// <param name="length"> The "typical" number of arguments expected by the function. Pass /// <c>-1</c> to use the number of arguments expected by the delegate. </param> internal ClrFunction(ObjectInstance prototype, Delegate delegateToCall, string name = null, int length = -1) : base(prototype) { // Initialize the [[Call]] method. this.callBinder = new JSBinder(new JSBinderMethod(delegateToCall.Method)); // If the delegate has a class instance, use that to call the method. this.thisBinding = delegateToCall.Target; // Add function properties. this.FastSetProperty("name", name != null ? name : this.callBinder.Name, PropertyAttributes.Configurable); this.FastSetProperty("length", length >= 0 ? length : this.callBinder.FunctionLength, PropertyAttributes.Configurable); //this.FastSetProperty("prototype", this.Engine.Object.Construct()); //this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable); }
// 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. m_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 = 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. m_callBinder = callBinderMethods.Count > 0 ? new JSBinder(callBinderMethods) : new JSBinder(new JSBinderMethod(new Func <object>(() => Undefined.Value).Method, JSFunctionFlags.None)); // Initialize the Construct function. m_constructBinder = constructBinderMethods.Count > 0 ? new JSBinder(constructBinderMethods) : new JSBinder(new JSBinderMethod(new Func <ObjectInstance>(() => Engine.Object.Construct()).Method, JSFunctionFlags.None)); // Add function properties. FastSetProperty("name", name, PropertyAttributes.Sealed, false); FastSetProperty("length", m_callBinder.FunctionLength, PropertyAttributes.Sealed, false); FastSetProperty("prototype", instancePrototype, PropertyAttributes.Sealed, false); instancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable, false); }