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 EmptyBinder();
// Initialize the Construct function.
if (constructBinderMethods.Count > 0)
this.constructBinder = new JSBinder(constructBinderMethods);
else
this.constructBinder = new EmptyBinder();
// Add function properties.
this.FastSetProperty("name", name, PropertyAttributes.Configurable);
this.FastSetProperty("length", this.callBinder.FunctionLength, PropertyAttributes.Configurable);
this.FastSetProperty("prototype", instancePrototype, PropertyAttributes.Sealed);
instancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable);
}