Files
yallie 9fa3874800 Added the contents of the archive.
Moved the original file to the archive subfolder.
2017-11-20 16:11:42 +03:00

1289 lines
60 KiB
C#

// ==++==
//
//
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are contained in the file
// named license.txt, which can be found in the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
//
// ==--==
namespace Microsoft.JScript
{
using Microsoft.JScript.Vsa;
using System;
using System.Diagnostics;
using System.Collections;
using System.Globalization;
using System.Reflection;
using System.Runtime.InteropServices.Expando;
public sealed class LateBinding{
private Object last_ir;
internal MemberInfo last_member;
internal MemberInfo[] last_members;
internal Object last_object;
private String name; //If this is null, the default indexed property should be called
public Object obj;
private bool checkForDebugger;
public LateBinding(String name)
: this(name, null, false){
}
public LateBinding(String name, Object obj)
: this(name, obj, false){
}
internal LateBinding(String name, Object obj, bool checkForDebugger){
this.last_ir = null;
this.last_member = null;
this.last_members = null;
this.last_object = null;
this.name = name;
this.obj = obj;
this.checkForDebugger = checkForDebugger;
}
internal MemberInfo BindToMember(){
Debug.Assert(this.obj != null && this.name != null);
if (this.obj == this.last_object && this.last_member != null)
return this.last_member;
BindingFlags flags = BindingFlags.Instance|BindingFlags.Public;
Object obj = this.obj;
Type t = obj.GetType();
TypeReflector tr = TypeReflector.GetTypeReflectorFor(t);
IReflect ir = null;
if (tr.ImplementsIReflect()){
ir = obj as ScriptObject;
if (ir != null){
if (obj is ClassScope)
flags = BindingFlags.Static|BindingFlags.Public;
}else{
ir = obj as Type;
if (ir != null)
flags = BindingFlags.Static|BindingFlags.Public;
else
ir = (IReflect)obj;
}
}else
ir = tr;
this.last_object = this.obj;
this.last_ir = ir;
MemberInfo[] members = this.last_members = ir.GetMember(this.name, flags);
this.last_member = LateBinding.SelectMember(members);
if (this.obj is Type){ //Add instance members of type Type to the member list
MemberInfo[] tmembers = Typeob.Type.GetMember(this.name, BindingFlags.Instance|BindingFlags.Public);
int n = 0, m = 0;
if (tmembers != null && (n = tmembers.Length) > 0){
if (members == null || (m = members.Length) == 0)
this.last_member = LateBinding.SelectMember(this.last_members = tmembers);
else{
MemberInfo[] jmembers = new MemberInfo[n + m];
ArrayObject.Copy(members, 0, jmembers, 0, m);
ArrayObject.Copy(tmembers, 0, jmembers, m, n);
this.last_member = LateBinding.SelectMember(this.last_members = jmembers);
}
}
}
return this.last_member;
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
public Object Call(Object[] arguments, bool construct, bool brackets, VsaEngine engine){
try{
if (this.name == null)
//Happens when (non simple expr)(args) is evaluated from Eval or the Debugger
return LateBinding.CallValue(this.obj, arguments, construct, brackets, engine,
((IActivationObject)engine.ScriptObjectStackTop()).GetDefaultThisObject(), JSBinder.ob, null, null);
else
return this.Call(JSBinder.ob, arguments, null, null, null, construct, brackets, engine);
}catch(TargetInvocationException e){
throw e.InnerException;
}
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
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 == Typeob.Object)
return LateBinding.CallMethod((MethodInfo)member, arguments, this.obj, binder, culture, namedParameters);
else if (dt == Typeob.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 == Typeob.Boolean)
return LateBinding.CallMethod((MethodInfo)member, arguments, Convert.ToBoolean(this.obj), binder, culture, namedParameters);
else if (dt == Typeob.StringObject || dt == Typeob.BooleanObject || dt == Typeob.NumberObject || brackets)
return LateBinding.CallMethod((MethodInfo)member, arguments, Convert.ToObject(this.obj, engine), binder, culture, namedParameters);
else if (dt == Typeob.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 (member.IsDefined(Typeob.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 (arguments.Length > 0 && ((PropertyInfo)member).GetIndexParameters().Length == 0){
Type rtype = ((PropertyInfo)member).PropertyType;
if (rtype == Typeob.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)
try{
return LateBinding.CallOneOfTheMembers(this.last_members, arguments, construct, this.obj, binder, culture, namedParameters, engine);
}catch(MissingMemberException){
//No suitable constructor or method or property getter, but the value of (this.obj).(this.name) might contain a callable thing, so carry on.
}
//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);
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
private static Object CallCOMObject(IReflect ir, String name, Object ob, Binder binder, Object[] arguments,
ParameterModifier[] modifiers, CultureInfo culture, String[] namedParameters,
bool construct, bool brackets, VsaEngine engine){
try{
try{
LateBinding.Change64bitIntegersToDouble(arguments);
BindingFlags flags =
BindingFlags.Public|BindingFlags.Instance|BindingFlags.Static|BindingFlags.OptionalParamBinding;
if (construct)
return ir.InvokeMember(name, flags|BindingFlags.CreateInstance, binder, ob, arguments, modifiers, culture, namedParameters);
else if (brackets){
// Expression like ob.name[args]. First try to invoke as an indexed property. If that
// results in a ArgumentException, try to evaluate (ob.name) and then invoke
// the default indexed property on the result.
try {
return ir.InvokeMember(name, flags|BindingFlags.GetProperty|BindingFlags.GetField, binder, ob, arguments, modifiers, culture, namedParameters);
}catch(TargetInvocationException){
Object ob1 = ir.InvokeMember(name, flags|BindingFlags.GetProperty|BindingFlags.GetField, binder, ob, new Object[0], modifiers, culture, new String[0]);
return LateBinding.CallValue(ob1, arguments, construct, brackets, engine, ob1, binder, culture, namedParameters);
}
}else{
int length = arguments == null ? 0 : arguments.Length;
if (namedParameters != null && namedParameters.Length > 0 && (namedParameters[0].Equals("[DISPID=-613]") || namedParameters[0].Equals("this")))
length--;
flags |= length > 0
? BindingFlags.InvokeMethod | BindingFlags.GetProperty
: BindingFlags.InvokeMethod;
return ir.InvokeMember(name, flags, binder, ob, arguments, modifiers, culture, namedParameters);
}
}catch(MissingMemberException){
if (brackets) //ob["x"]. Tried ob.Item()["x"] but failed. So return undefined.
return null;
else //ob("x"). Tried ob.Item()("x") but failed. Complain that ob is not a callable thing.
throw new JScriptException(JSError.FunctionExpected);
}
}catch(JScriptException e){
if ((e.Number & 0xFFFF) == (int)JSError.FunctionExpected){
//try to find a method on System.Object
MemberInfo[] members = Typeob.Object.GetMember(name, BindingFlags.Public|BindingFlags.Instance);
if (members != null && members.Length > 0)
return LateBinding.CallOneOfTheMembers(members, arguments, construct, ob, binder, culture, namedParameters, engine);
}
throw e;
}
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
private static Object CallMethod(MethodInfo method, Object[] arguments, Object thisob, Binder binder, CultureInfo culture, String[] namedParameters){
if (namedParameters != null && namedParameters.Length > 0)
if (arguments.Length >= namedParameters.Length)
arguments = JSBinder.ArrangeNamedArguments(method, arguments, namedParameters);
else
throw new JScriptException(JSError.MoreNamedParametersThanArguments);
Object[] newargs = LateBinding.LickArgumentsIntoShape(method.GetParameters(), arguments, binder, culture);
try{
Object result = method.Invoke(thisob, BindingFlags.SuppressChangeType, null, newargs, null);
if (newargs != arguments && newargs != null && arguments != null){
//Copy elements of newargs back to arguments, in case any of them were passed by reference
int n = arguments.Length;
int m = newargs.Length;
if (m < n) n = m;
for (int i = 0; i < n; i++) arguments[i] = newargs[i];
}
return result;
}catch(TargetException e){
ClassScope csc = thisob as ClassScope;
if (csc != null) return csc.FakeCallToTypeMethod(method, newargs, e);
throw;
}
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
internal static Object CallOneOfTheMembers(MemberInfo[] members, Object[] arguments, bool construct, Object thisob, Binder binder, CultureInfo culture, String[] namedParameters, VsaEngine engine){
//Note that SelectConstructor and SelectMethod take care of named parameters
if (construct){
ConstructorInfo cons = JSBinder.SelectConstructor(members, ref arguments, namedParameters);
if (cons != null){
if (cons.IsDefined(Typeob.JSFunctionAttribute, false)){
if (thisob is StackFrame) thisob = ((StackFrame)thisob).closureInstance;
int n = arguments.Length;
Object[] newArguments = new Object[n+1];
ArrayObject.Copy(arguments, 0, newArguments, 0, n);
newArguments[n] = thisob;
arguments = newArguments;
}
Object result = null;
JSConstructor jscons = cons as JSConstructor;
if (jscons != null)
result = jscons.Construct(thisob, LateBinding.LickArgumentsIntoShape(cons.GetParameters(), arguments, JSBinder.ob, culture));
else
result = cons.Invoke(BindingFlags.SuppressChangeType, null,
LateBinding.LickArgumentsIntoShape(cons.GetParameters(), arguments, JSBinder.ob, culture), null);
if (result is INeedEngine)
((INeedEngine)result).SetEngine(engine);
return result;
}
}else{
Object[] originalArguments = arguments;
MethodInfo meth = JSBinder.SelectMethod(members, ref arguments, namedParameters);
if (meth != null) {
if (meth is JSMethod )
return ((JSMethod)meth).Invoke(thisob, thisob, (BindingFlags)0, JSBinder.ob, arguments, null);
if (meth.IsDefined(Typeob.JSFunctionAttribute, false)){ //Dealing with a builtin function
if (!construct){
JSBuiltin biFunc = ((JSFunctionAttribute)meth.GetCustomAttributes(Typeob.JSFunctionAttribute, false)[0]).builtinFunction;
if (biFunc != 0){
IActivationObject iaob = thisob as IActivationObject;
if (iaob != null) thisob = iaob.GetDefaultThisObject();
return BuiltinFunction.QuickCall(arguments, thisob, biFunc, null, engine);
}
}
return LateBinding.CallValue(new BuiltinFunction(thisob, meth), arguments, construct, false, engine, thisob, JSBinder.ob, null, null);
}else{
Object[] args = LateBinding.LickArgumentsIntoShape(meth.GetParameters(), arguments, JSBinder.ob, culture);
if (thisob != null && !meth.DeclaringType.IsAssignableFrom(thisob.GetType())){
if (thisob is StringObject)
return meth.Invoke(((StringObject)thisob).value, BindingFlags.SuppressChangeType, null, args, null);
if (thisob is NumberObject)
return meth.Invoke(((NumberObject)thisob).value, BindingFlags.SuppressChangeType, null, args, null);
if (thisob is BooleanObject)
return meth.Invoke(((BooleanObject)thisob).value, BindingFlags.SuppressChangeType, null, args, null);
if (thisob is ArrayWrapper)
return meth.Invoke(((ArrayWrapper)thisob).value, BindingFlags.SuppressChangeType, null, args, null);
}
Object result = meth.Invoke(thisob, BindingFlags.SuppressChangeType, null, args, null);
if (args != originalArguments && arguments == originalArguments && args != null && arguments != null){
//Different because of optional parameters or param arrays. Update the original array in case there were call by reference parameters.
int n = arguments.Length;
int m = args.Length;
if (m < n) n = m;
for (int i = 0; i < n; i++) arguments[i] = args[i];
}
return result;
}
}
}
throw new MissingMemberException();
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
public static Object CallValue(Object thisob, Object val, Object[] arguments, bool construct, bool brackets, VsaEngine engine){
try{
return LateBinding.CallValue(val, arguments, construct, brackets, engine, thisob, JSBinder.ob, null, null);
}catch(TargetInvocationException e){
throw e.InnerException;
}
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
public static Object CallValue2(Object val, Object thisob, Object[] arguments, bool construct, bool brackets, VsaEngine engine){
try{
return LateBinding.CallValue(val, arguments, construct, brackets, engine, thisob, JSBinder.ob, null, null);
}catch(TargetInvocationException e){
throw e.InnerException;
}
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
internal static Object CallValue(Object val, Object[] arguments, bool construct, bool brackets, VsaEngine engine, Object thisob,
Binder binder, CultureInfo culture, String[] namedParameters){
if (construct){
if (val is ScriptFunction){
ScriptFunction fun = (ScriptFunction)val;
if (!brackets) goto old_style_behavior;
Object propVal = propVal = fun[arguments];
if (propVal != null)
return CallValue(propVal, new Object[0], true, false, engine, thisob, binder, culture, namedParameters);
Type t = (Type)TypeExpression.PredefinedType[fun.name];
if (t != null){ //It is a function that could be used in a type expression
int n = arguments.Length;
int[] indices = new int[n];
n = 0;
foreach (Object arg in arguments){
if (arg is Int32){
indices[n++] = (int)arg;
continue;
}
IConvertible ic = Convert.GetIConvertible(arg);
if (ic == null || !Convert.IsPrimitiveNumericTypeCode(ic.GetTypeCode())) goto old_style_behavior;
double d = ic.ToDouble(null);
int i = (int)d;
if (d != (double)i) goto old_style_behavior;
indices[n++] = i;
}
return System.Array.CreateInstance(t, indices);
}
old_style_behavior:
FunctionObject func = fun as FunctionObject;
if (func != null){
return func.Construct(thisob as JSObject, arguments == null ? new Object[0] : arguments);
}else{
Object result = fun.Construct(arguments == null ? new Object[0] : arguments);
JSObject jsob = result as JSObject;
if (jsob != null) jsob.outer_class_instance = thisob as JSObject;
return result;
}
}else if (val is ClassScope){
if (brackets)
return System.Array.CreateInstance(Typeob.Object, LateBinding.ToIndices(arguments));
JSObject result = (JSObject)LateBinding.CallOneOfTheMembers(((ClassScope)val).constructors, arguments, construct,
thisob, binder, culture, namedParameters, engine);
result.noExpando = ((ClassScope)val).noExpando;
return result;
}else if (val is Type){
Type t = (Type)val;
if (brackets) //we have "new val[x, y, z]" where val is a Type, so create an array of val.
return System.Array.CreateInstance(t, LateBinding.ToIndices(arguments));
ConstructorInfo[] cons = t.GetConstructors();
Object result = null;
if (cons == null || cons.Length == 0) //Happens for interop
result = Activator.CreateInstance(t, (BindingFlags)0, JSBinder.ob, arguments, null);
else
result = LateBinding.CallOneOfTheMembers(cons, arguments, construct, thisob, binder, culture, namedParameters, engine);
if (result is INeedEngine)
((INeedEngine)result).SetEngine(engine);
return result;
}else if (val is TypedArray && brackets)
return System.Array.CreateInstance(Typeob.Object, LateBinding.ToIndices(arguments));
}
if (brackets){
ScriptObject scrob = val as ScriptObject;
if (scrob != null){
Object v = scrob[arguments];
if (construct) return LateBinding.CallValue(thisob, v, new Object[0], true, false, engine);
return v;
}
}else{
if (val is ScriptFunction){
if (thisob is IActivationObject)
thisob = ((IActivationObject)thisob).GetDefaultThisObject();
return ((ScriptFunction)val).Call(arguments == null ? new Object[0] : arguments, thisob, binder, culture);
}else if (val is Delegate)
return CallMethod(((Delegate)val).Method, arguments, thisob, binder, culture, namedParameters);
else if (val is MethodInfo)
return CallMethod((MethodInfo)val, arguments, thisob, binder, culture, namedParameters);
else if (val is Type && arguments.Length == 1)
return Convert.CoerceT(arguments[0], (Type)val, true);
else if (val is ClassScope){
if (arguments == null || arguments.Length != 1)
throw new JScriptException(JSError.FunctionExpected);
if (((ClassScope)val).HasInstance(arguments[0])) return arguments[0];
throw new InvalidCastException(null);
}else if (val is TypedArray && arguments.Length == 1)
return Convert.Coerce(arguments[0], val, true);
else if (val is ScriptObject)
throw new JScriptException(JSError.FunctionExpected);
else if (val is MemberInfo[])
return LateBinding.CallOneOfTheMembers((MemberInfo[])val, arguments, construct, thisob, binder, culture, namedParameters, engine);
}
if (val != null){
System.Array arr = val as System.Array;
if (arr != null){
if (arguments.Length != arr.Rank)
throw new JScriptException(JSError.IncorrectNumberOfIndices);
return arr.GetValue(LateBinding.ToIndices(arguments));
}
//See if val has a default indexed property that we can call
val = Convert.ToObject(val, engine);
ScriptObject scrob = val as ScriptObject;
if (scrob != null)
if (brackets)
return scrob[arguments];
else{
ScriptFunction sf = scrob as ScriptFunction;
if (sf != null){
IActivationObject iaob = thisob as IActivationObject;
if (iaob != null) thisob = iaob.GetDefaultThisObject();
return sf.Call(arguments == null ? new Object[0] : arguments, thisob, binder, culture);
}
throw new JScriptException(JSError.InvalidCall);
}
IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(val, VsaEngine.executeForJSEE);
if (ir != null){
if (brackets){
String name = String.Empty;
int n = arguments.Length;
if (n > 0)
name = Convert.ToString(arguments[n-1]);
return CallCOMObject(ir, name, val, binder, null, null, culture, namedParameters, false, true, engine);
}
if (!(val is IReflect))
return CallCOMObject(ir, String.Empty, val, binder, arguments, null, culture, namedParameters, false, brackets, engine);
// Pass in the 'this' object as an additional named parameter
Object[] arguments2 = new Object[(arguments != null ? arguments.Length : 0) + 1];
arguments2[0] = thisob;
if (arguments != null)
ArrayObject.Copy(arguments, 0, arguments2, 1, arguments.Length);
String[] namedParameters2 = new String[(namedParameters != null ? namedParameters.Length : 0) + 1];
namedParameters2[0] = "[DISPID=-613]";
if (namedParameters != null)
ArrayObject.Copy(namedParameters, 0, namedParameters2, 1, namedParameters.Length);
return CallCOMObject(ir, "[DISPID=0]", val, binder, arguments2, null, culture, namedParameters2, false, brackets, engine);
}
MemberInfo[] defaultMembers = TypeReflector.GetTypeReflectorFor(val.GetType()).GetDefaultMembers();
if (defaultMembers != null && defaultMembers.Length > 0){
MethodInfo meth = JSBinder.SelectMethod(defaultMembers, ref arguments, namedParameters); //This also selects property getters
if (meth != null)
return LateBinding.CallMethod(meth, arguments, val, binder, culture, namedParameters);
}
}
throw new JScriptException(JSError.FunctionExpected);
}
private static void Change64bitIntegersToDouble(Object[] arguments){
if (arguments == null) return;
for (int i = 0, n = arguments.Length; i < n; i++){
Object val = arguments[i];
IConvertible ic = Convert.GetIConvertible(val);
TypeCode code = Convert.GetTypeCode(val, ic);
switch(code){
case TypeCode.Int64:
case TypeCode.UInt64:
arguments[i] = ic.ToDouble(null);
break;
}
}
}
public bool Delete(){
return LateBinding.DeleteMember(this.obj, this.name);
}
public static bool DeleteMember(Object obj, String name){
if (name == null || obj == null) return false;
if (obj is ScriptObject)
return ((ScriptObject)obj).DeleteMember(name);
if (obj is IExpando)
try{
IExpando eob = (IExpando)obj;
MemberInfo[] members = eob.GetMember(name, BindingFlags.Instance|BindingFlags.Public);
MemberInfo member = LateBinding.SelectMember(members);
if (member != null){
eob.RemoveMember(member);
return true;
}
return false;
}catch{
return false;
}
if (obj is IDictionary){
IDictionary dict = (IDictionary)obj;
if (dict.Contains(name)){
dict.Remove(name);
return true;
}
return false;
}
Type obType = obj.GetType();
MethodInfo deleteOp = TypeReflector.GetTypeReflectorFor(obType).GetMethod(
"op_Delete", BindingFlags.ExactBinding|BindingFlags.Public|BindingFlags.Static, null, new Type[]{obType, typeof(Object[])}, null);
if (deleteOp == null || (deleteOp.Attributes & MethodAttributes.SpecialName) == 0 || deleteOp.ReturnType != Typeob.Boolean)
return false; //This is in the spirit of the spec, but not backwards compatible with JS5. The latter throws an exception.
else
return (bool)deleteOp.Invoke(null, new Object[]{obj, new Object[]{name}});
}
internal static bool DeleteValueAtIndex(Object obj, ulong index){
if (obj is ArrayObject && index < UInt32.MaxValue)
return ((ArrayObject)obj).DeleteValueAtIndex((uint)index);
return LateBinding.DeleteMember(obj, index.ToString());
}
private static IReflect GetIRForObjectThatRequiresInvokeMember(Object obj, bool checkForDebugger){
return null;
}
private static IReflect GetIRForObjectThatRequiresInvokeMember(Object obj, bool checkForDebugger, TypeCode tcode){
return tcode != TypeCode.Object ? null : LateBinding.GetIRForObjectThatRequiresInvokeMember(obj, checkForDebugger);
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
internal static Object GetMemberValue(Object obj, String name){
if (obj is ScriptObject)
return ((ScriptObject)obj).GetMemberValue(name);
//Create a LateBinding instance so that we can reuse the ugly logic in BindToMember to get the members.
LateBinding lb = new LateBinding(name, obj);
return lb.GetNonMissingValue();
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
internal static Object GetMemberValue2(Object obj, String name){
if (obj is ScriptObject)
return ((ScriptObject)obj).GetMemberValue(name);
//Create a LateBinding instance so that we can reuse the ugly logic in BindToMember to get the members.
LateBinding lb = new LateBinding(name, obj);
return lb.GetValue();
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
internal static Object GetMemberValue(Object obj, String name, MemberInfo member, MemberInfo[] members){
if (member != null){
try{
switch(member.MemberType){
case MemberTypes.Field:
Object val = ((FieldInfo)member).GetValue(obj);
Type et = obj as Type;
if (et != null && et.IsEnum)
try{
val = Enum.ToObject(et, ((IConvertible)val).ToUInt64(null));
}catch{}
return val;
case MemberTypes.Property:
PropertyInfo prop = (PropertyInfo)member;
if (prop.DeclaringType == Typeob.ArrayObject){
ArrayObject aob = obj as ArrayObject;
if (aob != null) return aob.length;
}else if (prop.DeclaringType == Typeob.StringObject){
StringObject strob = obj as StringObject;
if (strob != null) return strob.length;
}
return JSProperty.GetValue(prop, obj, null);
case MemberTypes.Event: return null;
case MemberTypes.NestedType: return member;
}
}catch(Exception e){
if (obj is StringObject)
return LateBinding.GetMemberValue(((StringObject)obj).value, name, member, members);
if (obj is NumberObject)
return LateBinding.GetMemberValue(((NumberObject)obj).value, name, member, members);
if (obj is BooleanObject)
return LateBinding.GetMemberValue(((BooleanObject)obj).value, name, member, members);
if (obj is ArrayWrapper)
return LateBinding.GetMemberValue(((ArrayWrapper)obj).value, name, member, members);
throw e;
}
}
if (members != null && members.Length > 0){
//Special case check for methods on builtin objects
if (members.Length == 1 && members[0].MemberType == MemberTypes.Method){
MethodInfo meth = (MethodInfo)members[0];
Type dt = meth.DeclaringType;
if (dt == Typeob.GlobalObject ||
(dt != null && dt != Typeob.StringObject && dt != Typeob.NumberObject && dt != Typeob.BooleanObject && dt.IsSubclassOf(Typeob.JSObject))){
//This only happens in fast mode. We could add InitOnly fields to the fast predefined objects and initialize them
//with instances of BuiltinFunction objects, in which case we would never get here, but we would like to avoid
//the start up cost of allocating these objects, particularly if they end up never being used (the expected common case).
return Globals.BuiltinFunctionFor(obj, meth);
}
}
return new FunctionWrapper(name, obj, members);
}
//Check for expando field on ScriptObject, despite the fact that it did not show up in member.
//This could happen if the object is referred to in a loop and the expando was created after the first time the reference is encountered
//It is also need to get to the $ properties on RegExp
if (obj is ScriptObject)
return ((ScriptObject)obj).GetMemberValue(name);
//A namespace does not implement IReflect and hence cannot deliver a member for the cache. Check it now.
if (obj is Namespace){
Namespace ns = (Namespace)obj;
String qualid = ns.Name+"."+name;
Type type = ns.GetType(qualid);
if (type != null) return type;
return Namespace.GetNamespace(qualid, ns.engine);
}
//Handle COM objects and IExpando objects.
IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(obj, true);
if (ir != null){
try{
const BindingFlags flags =
BindingFlags.Public|BindingFlags.Instance|BindingFlags.OptionalParamBinding|
BindingFlags.GetProperty|BindingFlags.GetField;
return ir.InvokeMember(name, flags, JSBinder.ob, obj, null, null, null, null);
}catch(MissingMemberException){
}
}
//If we get here the object does not have such a member
return Missing.Value;
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
public Object GetNonMissingValue(){
Object result = this.GetValue();
if (result is Missing)
return null;
return result;
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
internal Object GetValue(){
this.BindToMember(); //Do a GetMember call and remember the result of the lookup for next time around
return LateBinding.GetMemberValue(this.obj, this.name, this.last_member, this.last_members);
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
public Object GetValue2(){
Object result = this.GetValue();
if (result == Missing.Value){
throw new JScriptException(JSError.UndefinedIdentifier, new Context(new DocumentContext("", null), this.name));
}
return result;
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
internal static Object GetValueAtIndex(Object obj, ulong index){
if (obj is ScriptObject)
if (index < UInt32.MaxValue)
return ((ScriptObject)obj).GetValueAtIndex((uint)index);
else
return ((ScriptObject)obj).GetMemberValue(index.ToString());
default_property_case:
if (obj is IList)
checked {return ((IList)obj)[(int)index];}
if (obj is Array)
checked {return ((Array)obj).GetValue((int)index);}
Type type = obj.GetType();
if (type.IsCOMObject || obj is IReflect || index > Int32.MaxValue)
return LateBinding.GetMemberValue(obj, index.ToString());
//Assume that the object does not itself have a field/property with numerical name.
//See if the object has a default indexed property, or default property that results in an Array or List and work with that.
MethodInfo getter = JSBinder.GetDefaultPropertyForArrayIndex(type, (int)index, null, false);
if (getter != null){
ParameterInfo[] pars = getter.GetParameters();
if (pars == null || pars.Length == 0){
obj = getter.Invoke(obj, BindingFlags.SuppressChangeType, null, null, null);
goto default_property_case;
}else
return getter.Invoke(obj, (BindingFlags)0, JSBinder.ob, new Object[]{(int)index}, null);
}
return Missing.Value;
}
//Do not call this method for arguments that are going out to COM2 objects via interop.
private static Object[] LickArgumentsIntoShape(ParameterInfo[] pars, Object[] arguments, Binder binder, CultureInfo culture){
if (arguments == null)
return null;
int formals = pars.Length;
if (formals == 0)
return null;
Object[] newArgs = arguments;
int actuals = arguments.Length;
if (actuals != formals)
newArgs = new Object[formals];
int m = formals-1; //Position of last formal param
int k = actuals < m ? actuals : m; //Number of formal params that have corresponding actual arguments, bar the last one, which may be a varArg array.
//Copy all actual args that match formal param, bar the last one. Change DBNull to null. Coerce actual value to formal param type.
for (int i = 0; i < k; i++){
Object arg = arguments[i];
if (arg is DBNull)
newArgs[i] = null; //Outside of the world of OLE Variants, undefined == null == the null pointer.
else
newArgs[i] = binder.ChangeType(arguments[i], pars[i].ParameterType, culture);
}
//Supply default values for all formal params, bar the last one, that do not have corresponding actual arguments
for (int i = k; i < m; i++){
Object dv = pars[i].DefaultValue;
if (dv == System.Convert.DBNull) //No default value was specified
dv = binder.ChangeType(null, pars[i].ParameterType, culture); //Substitute undefined
newArgs[i] = dv;
}
//If the last formal param is a vararg param, treat it specially.
if (pars[m].IsDefined(Typeob.ParamArrayAttribute, false)){
int numVarArgs = actuals - m;
if (numVarArgs < 0) numVarArgs = 0;
Type t = pars[m].ParameterType.GetElementType();
Array pa = Array.CreateInstance(t, numVarArgs);
for (int j = 0; j < numVarArgs; j++)
pa.SetValue(binder.ChangeType(arguments[j+m], t, culture), j);
newArgs[m] = pa;
}else if (actuals < formals){
Object dv = pars[m].DefaultValue;
if (dv == System.Convert.DBNull) //No default value was specified
dv = binder.ChangeType(null, pars[m].ParameterType, culture); //Substitute undefined
newArgs[m] = dv;
}else
newArgs[m] = binder.ChangeType(arguments[m], pars[m].ParameterType, culture);
return newArgs;
}
internal static MemberInfo SelectMember(MemberInfo[] mems){
if (mems == null) return null;
MemberInfo result = null;
foreach (MemberInfo mem in mems){
switch(mem.MemberType){
case MemberTypes.Field:
if (result == null || result.MemberType != MemberTypes.Field)
result = mem;
break;
case MemberTypes.Property:
if (result == null || (result.MemberType != MemberTypes.Field && result.MemberType != MemberTypes.Property)){
ParameterInfo[] pars = ((PropertyInfo)mem).GetIndexParameters();
if (pars != null && pars.Length == 0)
result = mem;
}
break;
case MemberTypes.TypeInfo:
case MemberTypes.NestedType:
if (result == null)
result = mem;
break;
}
}
return result;
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
internal void SetIndexedDefaultPropertyValue(Object ob, Object[] arguments, Object value){
ScriptObject scrob = ob as ScriptObject;
if (scrob != null){
scrob[arguments] = value;
return;
}
System.Array arr = ob as System.Array;
if (arr != null){
if (arguments.Length != arr.Rank)
throw new JScriptException(JSError.IncorrectNumberOfIndices);
arr.SetValue(value, LateBinding.ToIndices(arguments));
return;
}
TypeCode tcode = Convert.GetTypeCode(ob);
if (Convert.NeedsWrapper(tcode)) return; //senseless assignment to implicit wrapper. Do nothing.
IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(ob, this.checkForDebugger, tcode);
if (ir != null){
try{
int n = arguments.Length + 1;
Object[] newargs = new Object[n];
ArrayObject.Copy(arguments, 0, newargs, 0, n-1);
newargs[n-1] = value;
const BindingFlags flags =
BindingFlags.Public|BindingFlags.Instance|BindingFlags.OptionalParamBinding|
BindingFlags.SetProperty|BindingFlags.SetField;
ir.InvokeMember(String.Empty, flags, JSBinder.ob, ob, newargs, null, null, null);
return;
}catch(MissingMemberException){
throw new JScriptException(JSError.OLENoPropOrMethod);
}
}
MemberInfo[] defaultMembers = TypeReflector.GetTypeReflectorFor(ob.GetType()).GetDefaultMembers();
if (defaultMembers != null && defaultMembers.Length > 0){
PropertyInfo prop = JSBinder.SelectProperty(defaultMembers, arguments);
if (prop != null){
MethodInfo setter = JSProperty.GetSetMethod(prop, false);
if (setter != null){
arguments = LateBinding.LickArgumentsIntoShape(prop.GetIndexParameters(), arguments, JSBinder.ob, null);
value = Convert.CoerceT(value, prop.PropertyType);
int n = arguments.Length + 1;
Object[] newargs = new Object[n];
ArrayObject.Copy(arguments, 0, newargs, 0, n-1);
newargs[n-1] = value;
setter.Invoke(ob, newargs);
return;
}
}
}
throw new JScriptException(JSError.OLENoPropOrMethod);
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
internal void SetIndexedPropertyValue(Object[] arguments, Object value){
if (this.obj == null)
throw new JScriptException(JSError.ObjectExpected);
if (this.name == null){
this.SetIndexedDefaultPropertyValue(this.obj, arguments, value);
return;
}
MemberInfo member = this.BindToMember(); //Do a GetMember call and remember the result of the lookup for next time around
//If the object has any members called this.name, we try to find a suitable indexed property.
if (this.last_members != null && this.last_members.Length > 0){
PropertyInfo prop = JSBinder.SelectProperty(this.last_members, arguments);
if (prop != null){
if (arguments.Length > 0 && prop.GetIndexParameters().Length == 0){
//Might be a parameterless property that results in an object that has a indexed property that can be assigned to
MethodInfo getter = JSProperty.GetGetMethod(prop, false);
if (getter != null){
LateBinding.SetIndexedPropertyValueStatic(getter.Invoke(this.obj, null), arguments, value);
return;
}
}
arguments = LateBinding.LickArgumentsIntoShape(prop.GetIndexParameters(), arguments, JSBinder.ob, null);
value = Convert.CoerceT(value, prop.PropertyType);
JSProperty.SetValue(prop, this.obj, value, arguments);
return;
}
}
TypeCode tcode = Convert.GetTypeCode(obj);
if (Convert.NeedsWrapper(tcode)) return; //senseless assignment to implicit wrapper. Do nothing.
IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(obj, this.checkForDebugger, tcode);
if (ir != null){
int n = arguments.Length + 1;
Object[] newargs = new Object[n];
ArrayObject.Copy(arguments, 0, newargs, 0, n-1);
newargs[n-1] = value;
const BindingFlags flags =
BindingFlags.Public|BindingFlags.Instance|BindingFlags.OptionalParamBinding|
BindingFlags.SetProperty|BindingFlags.SetField;
ir.InvokeMember(this.name, flags, JSBinder.ob, this.obj, newargs, null, null, null);
return;
}
//<ob.foo> might be an object that has a default indexed property
Object ob = this.GetValue();
if (ob != null && !(ob is Missing)){
this.SetIndexedDefaultPropertyValue(ob, arguments, value);
return;
}
//Give up
throw new JScriptException(JSError.OLENoPropOrMethod);
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
public static void SetIndexedPropertyValueStatic(Object obj, Object[] arguments, Object value){
if (obj == null)
throw new JScriptException(JSError.ObjectExpected);
ScriptObject scrob = obj as ScriptObject;
if (scrob != null){
scrob[arguments] = value;
return;
}
Array arr = obj as Array;
if (arr != null){
if (arguments.Length != arr.Rank)
throw new JScriptException(JSError.IncorrectNumberOfIndices);
arr.SetValue(value, LateBinding.ToIndices(arguments));
return;
}
TypeCode tcode = Convert.GetTypeCode(obj);
if (Convert.NeedsWrapper(tcode)) return; //senseless assignment to implicit wrapper. Do nothing.
IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(obj, true, tcode); //Either called from IL, or on an type object
if (ir != null){
//Legacy behavior is to convert the last argument to a string and treat it as the name of the property being set
String name = String.Empty;
int n = arguments.Length;
if (n > 0)
name = Convert.ToString(arguments[n-1]);
const BindingFlags flags =
BindingFlags.Public|BindingFlags.Instance|BindingFlags.OptionalParamBinding|
BindingFlags.SetProperty|BindingFlags.SetField;
ir.InvokeMember(name, flags, JSBinder.ob, obj, new Object[]{value}, null, null, null);
return;
}
MemberInfo[] defaultMembers = TypeReflector.GetTypeReflectorFor(obj.GetType()).GetDefaultMembers();
if (defaultMembers != null && defaultMembers.Length > 0){
PropertyInfo prop = JSBinder.SelectProperty(defaultMembers, arguments);
if (prop != null){
MethodInfo setter = JSProperty.GetSetMethod(prop, false);
if (setter != null){
arguments = LateBinding.LickArgumentsIntoShape(prop.GetIndexParameters(), arguments, JSBinder.ob, null);
value = Convert.CoerceT(value, prop.PropertyType);
int n = arguments.Length + 1;
Object[] newargs = new Object[n];
ArrayObject.Copy(arguments, 0, newargs, 0, n-1);
newargs[n-1] = value;
setter.Invoke(obj, newargs);
return;
}
}
}
throw new JScriptException(JSError.OLENoPropOrMethod);
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
private static void SetMember(Object obj, Object value, MemberInfo member){
switch(member.MemberType){
case MemberTypes.Field:
FieldInfo field = (FieldInfo)member;
if (!field.IsLiteral && !field.IsInitOnly){
if (field is JSField)
field.SetValue(obj, value);
else
field.SetValue(obj, Convert.CoerceT(value, field.FieldType), BindingFlags.SuppressChangeType, null, null);
}
return;
case MemberTypes.Property:
PropertyInfo property = (PropertyInfo)member;
if (property is JSProperty || property is JSWrappedProperty){
property.SetValue(obj, value, null);
return;
}
MethodInfo setMeth = JSProperty.GetSetMethod(property, false);
if (setMeth != null)
try{
setMeth.Invoke(obj, BindingFlags.SuppressChangeType, null, new Object[]{Convert.CoerceT(value, property.PropertyType)}, null);
}catch(TargetInvocationException e){
throw e.InnerException;
}
return;
}
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
internal static void SetMemberValue(Object obj, String name, Object value){
if (obj is ScriptObject){
((ScriptObject)obj).SetMemberValue(name, value);
return;
}
LateBinding lb = new LateBinding(name, obj);
lb.SetValue(value);
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
internal static void SetMemberValue(Object obj, String name, Object value, MemberInfo member, MemberInfo[] members){
if (member != null){
LateBinding.SetMember(obj, value, member);
return;
}
if (obj is ScriptObject){ //Create an expando the fast way. Also needed for $ properties on RegExp
((ScriptObject)obj).SetMemberValue(name, value);
return;
}
TypeCode tcode = Convert.GetTypeCode(obj);
if (Convert.NeedsWrapper(tcode)) return; //senseless assignment to implicit wrapper. Do nothing.
IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(obj, true, tcode);
if (ir != null){
try{
Object[] args = new Object[]{value};
IConvertible iconv = value as IConvertible;
//BindingFlags.SetProperty makes interop call with DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF .
BindingFlags flags = BindingFlags.Public|BindingFlags.Instance|BindingFlags.OptionalParamBinding|
BindingFlags.SetProperty|BindingFlags.SetField;
ir.InvokeMember(name, flags, JSBinder.ob, obj, args, null, null, null);
return;
}catch(MissingMemberException){
}
}
if (obj is IExpando){ //Create an expando the slow way
PropertyInfo prop = ((IExpando)obj).AddProperty(name);
if (prop != null)
prop.SetValue(obj, value, null);
else{
FieldInfo field = ((IExpando)obj).AddField(name);
if (field != null){
field.SetValue(obj, value);
}
}
return;
}
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
internal static void SetValueAtIndex(Object obj, ulong index, Object value){
if (obj is ScriptObject){
if (index < UInt32.MaxValue)
((ScriptObject)obj).SetValueAtIndex((uint)index, value);
else
((ScriptObject)obj).SetMemberValue(index.ToString(), value);
return;
}
default_property_case:
if (obj is IList){
IList list = (IList)obj;
if (index < (ulong)list.Count)
list[(int)index] = value;
else
list.Insert((int)index, value);
return;
}
if (obj is Array){
checked{((Array)obj).SetValue(Convert.CoerceT(value, obj.GetType().GetElementType()), (int)index);}
return;
}
Type type = obj.GetType();
if (type.IsCOMObject || obj is IReflect || index > Int32.MaxValue){
LateBinding.SetMemberValue(obj, index.ToString(), value);
return;
}
//Assume that the object does not itself have a field/property with numerical name.
//See if the object has a default indexed property, or default property that results in an Array or List and work with that.
MethodInfo setter = JSBinder.GetDefaultPropertyForArrayIndex(type, (int)index, null, true);
if (setter != null){
ParameterInfo[] pars = setter.GetParameters();
if (pars == null || pars.Length == 0){
obj = setter.Invoke(obj, BindingFlags.SuppressChangeType, null, null, null);
goto default_property_case;
}else
setter.Invoke(obj, (BindingFlags)0, JSBinder.ob, new Object[]{(int)index, value}, null);
}
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
public void SetValue(Object value){
this.BindToMember(); //Do a GetMember call and remember the result of the lookup for next time around
LateBinding.SetMemberValue(this.obj, this.name, value, this.last_member, this.last_members);
}
internal static void SwapValues(Object obj, uint left, uint right){
if (obj is JSObject){
((JSObject)obj).SwapValues(left, right);
return;
}
if (obj is IList){
IList list = (IList)obj;
Object temp = list[(int)left];
list[(int)left] = list[(int)right];
list[(int)right] = temp;
return;
}
if (obj is Array){
Array arr = (Array)obj;
Object temp = arr.GetValue((int)left);
arr.SetValue(arr.GetValue((int)right), (int)left);
arr.SetValue(temp, (int)right);
return;
}
if (obj is IExpando){
String left_name = System.Convert.ToString(left);
String right_name = System.Convert.ToString(right);
IExpando eob = (IExpando)obj;
FieldInfo left_field = eob.GetField(left_name, BindingFlags.Instance|BindingFlags.Public);
FieldInfo right_field = eob.GetField(right_name, BindingFlags.Instance|BindingFlags.Public);
if (left_field == null)
if (right_field == null)
return;
else
try{
left_field = eob.AddField(left_name);
left_field.SetValue(obj, right_field.GetValue(obj));
eob.RemoveMember(right_field);
}catch{
throw new JScriptException(JSError.ActionNotSupported);
}
else if (right_field == null)
try{
right_field = eob.AddField(right_name);
right_field.SetValue(obj, left_field.GetValue(obj));
eob.RemoveMember(left_field);
}catch{
throw new JScriptException(JSError.ActionNotSupported);
}
Object temp = left_field.GetValue(obj);
left_field.SetValue(obj, right_field.GetValue(obj));
right_field.SetValue(obj, temp);
return;
}
Object lval = LateBinding.GetValueAtIndex(obj, left);
Object rval = LateBinding.GetValueAtIndex(obj, right);
if (lval is Missing)
LateBinding.DeleteValueAtIndex(obj, right);
else
LateBinding.SetValueAtIndex(obj, right, lval);
if (rval is Missing)
LateBinding.DeleteValueAtIndex(obj, left);
else
LateBinding.SetValueAtIndex(obj, left, rval);
}
private static int[] ToIndices(Object[] arguments){
int n = arguments.Length;
int[] result = new int[n];
for (int i = 0; i < n; i++)
result[i] = Convert.ToInt32(arguments[i]);
return result;
}
}
}