internal Object Call(Binder binder, Object[] arguments, ParameterModifier[] modifiers, CultureInfo culture,
String[] namedParameters, bool construct, bool brackets, VsaEngine engine){
MemberInfo member = this.BindToMember(); //Do a GetMember call and remember the result of the lookup for next time around
//On ScriptObjects, fields/properties pre-empt everything else. Call whatever is the value of the field/property. If it is junk, throw an exception.
if (this.obj is ScriptObject || this.obj is GlobalObject){
//Handle WithObjects that wrap COMObjects specially
if (this.obj is WithObject){
Object wob = ((WithObject)this.obj).contained_object;
if (!(wob is ScriptObject)){
IReflect irw = LateBinding.GetIRForObjectThatRequiresInvokeMember(wob, VsaEngine.executeForJSEE);
if (irw != null)
return LateBinding.CallCOMObject(irw, this.name, wob, binder, arguments, modifiers, culture, namedParameters, construct, brackets, engine);
}
}
if (member is FieldInfo)
return LateBinding.CallValue(((FieldInfo)member).GetValue(this.obj), arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
else if (member is PropertyInfo && !(member is JSProperty)){ //JSProperty comes up when running the evaluator and using proper properties.
if (!brackets){
JSWrappedPropertyAndMethod propAndMethod = member as JSWrappedPropertyAndMethod;
if (propAndMethod != null){
BindingFlags flags = arguments == null || arguments.Length == 0
? BindingFlags.InvokeMethod
: BindingFlags.InvokeMethod | BindingFlags.GetProperty;
return propAndMethod.Invoke(this.obj, flags, JSBinder.ob, arguments, null);
}
}
return LateBinding.CallValue(JSProperty.GetValue((PropertyInfo)member, this.obj, null), arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
}
//The code paths below happen because Lookup and Member set last_member. Without the cache, BindToMember will not deliver a MethodInfo.
else if (member is MethodInfo){
if (member is JSMethod)
if (construct)
return ((JSMethod)member).Construct(arguments);
else
return ((JSMethod)member).Invoke(this.obj, this.obj, (BindingFlags)0, JSBinder.ob, arguments, null);
else{
Type dt = member.DeclaringType;
if (dt == typeof(Object))
return LateBinding.CallMethod((MethodInfo)member, arguments, this.obj, binder, culture, namedParameters);
else if (dt == typeof(String))
return LateBinding.CallMethod((MethodInfo)member, arguments, Convert.ToString(this.obj), binder, culture, namedParameters);
else if (Convert.IsPrimitiveNumericType(dt))
return LateBinding.CallMethod((MethodInfo)member, arguments, Convert.CoerceT(this.obj, dt), binder, culture, namedParameters);
else if (dt == typeof(Boolean))
return LateBinding.CallMethod((MethodInfo)member, arguments, Convert.ToBoolean(this.obj), binder, culture, namedParameters);
else if (dt == typeof(StringObject) || dt == typeof(BooleanObject) || dt == typeof(NumberObject) || brackets)
return LateBinding.CallMethod((MethodInfo)member, arguments, Convert.ToObject(this.obj, engine), binder, culture, namedParameters);
else if (dt == typeof(GlobalObject) && ((MethodInfo)member).IsSpecialName)
return LateBinding.CallValue(((MethodInfo)member).Invoke(this.obj, null), arguments, construct, false, engine, this.obj, JSBinder.ob, null, null);
else if (!(this.obj is ClassScope)){
if (CustomAttribute.IsDefined(member, typeof(JSFunctionAttribute), false)){
FieldInfo f = LateBinding.SelectMember(this.last_members) as FieldInfo;
if (f != null){ //Field holds a closure, call the closure
Object obj = this.obj;
if (!(obj is Closure))
obj = f.GetValue(this.obj);
return LateBinding.CallValue(obj, arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
}
}
return LateBinding.CallValue(new BuiltinFunction(this.obj, (MethodInfo)member), arguments, construct, false, engine, this.obj, JSBinder.ob, null, null);
}
}
}
}
MethodInfo meth = member as MethodInfo;
if (meth != null) //Inside the evaluator, and dealing with an early bound method
//Get here because of EvaluateAsLateBinding in Lookup and Member. BindToMember will not have set this.member to be a method
return LateBinding.CallMethod(meth, arguments, this.obj, binder, culture, namedParameters);
JSConstructor jscons = member as JSConstructor;
if (jscons != null) //Inside the evaluator, and dealing with an early bound constructor
return LateBinding.CallValue(jscons.cons, arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
if (member is Type) //Inside the evaluator and dealing with early bound conversion
return LateBinding.CallValue(member, arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
if (member is ConstructorInfo) //Inside the evaluator, and dealing with an early bound constructor
return LateBinding.CallOneOfTheMembers(new MemberInfo[]{this.last_member}, arguments, true, this.obj, binder, culture, namedParameters, engine);
if (!construct && member is PropertyInfo){
//Might be a parameterless property that results in an object that has a default method or default indexed property that can be called with the params
//Need to special case this, otherwise the next if will end up calling the parameterless property getter, discarding the parameters
if (((PropertyInfo)member).GetIndexParameters().Length == 0){
Type rtype = ((PropertyInfo)member).PropertyType;
if (rtype == typeof(Object)){
MethodInfo getter = JSProperty.GetGetMethod((PropertyInfo)member, false);
if (getter != null){
Object ob = getter.Invoke(this.obj, null);
return LateBinding.CallValue(ob, arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
}
}
MemberInfo[] defaultMembers = TypeReflector.GetTypeReflectorFor(rtype).GetDefaultMembers();
if (defaultMembers != null && defaultMembers.Length > 0){
MethodInfo getter = JSProperty.GetGetMethod((PropertyInfo)member, false);
if (getter != null){
Object ob = getter.Invoke(this.obj, null);
return LateBinding.CallOneOfTheMembers(defaultMembers, arguments, false, ob, binder, culture, namedParameters, engine);
}
}
}
}
//Otherwise, if there are members, we give preference to constructors, methods and properties with matching formal parameter lists.
if (this.last_members != null && this.last_members.Length > 0)
{
bool memberCalled;
object retval = LateBinding.CallOneOfTheMembers(this.last_members, arguments, construct, this.obj, binder, culture, namedParameters, engine, out memberCalled);
if (memberCalled)
return retval;
//Fall through if no suitable constructor or method or property getter because the value of (this.obj).(this.name) might contain a callable thing.
}
//If the object is an IDispatch(Ex) use InvokeMember to do the call
//In all other cases we can assume that BindToMember has already found all the members that are to be found.
IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(this.obj, VsaEngine.executeForJSEE);
if (ir != null)
return LateBinding.CallCOMObject(ir, this.name, this.obj, binder, arguments, modifiers, culture, namedParameters, construct, brackets, engine);
//If the object has a field or parameterless property called this.name, we have to try and call the value of that field or property
Object value = LateBinding.GetMemberValue(this.obj, this.name, this.last_member, this.last_members);
if (!(value is Missing))
return LateBinding.CallValue(value, arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
//Give up
if (brackets)
if (this.obj is IActivationObject)
throw new JScriptException(JSError.ObjectExpected);
else
throw new JScriptException(JSError.OLENoPropOrMethod);
else
throw new JScriptException(JSError.FunctionExpected);
}