private static bool _method_filter(MethodBase method, call_conditions cond) { var parameters = method.GetParameters(); //Hide Sctx parameter if (_sctx_hack(parameters, cond)) { var relevantParameters = new ParameterInfo[parameters.Length - 1]; Array.Copy(parameters, 1, relevantParameters, 0, relevantParameters.Length); parameters = relevantParameters; } //Criteria No.1: The number of arguments has to match the number of parameters if (cond.Args.Length != parameters.Length) return false; //Criteria No.2: All Type-Locked arguments must match without a conversion for (var i = 0; i < parameters.Length; i++) { if (cond.Args[i].IsTypeLocked) { var P = parameters[i].ParameterType; var A = cond.Args[i].ClrType; if (!(P.Equals(A) || P.IsAssignableFrom(A))) //Neiter Equal nor assignable return false; } } //optional Criteria No.3: Return types must match if (cond.returnType != null && method is MethodInfo) { var methodEx = method as MethodInfo; if (!(methodEx.ReturnType.Equals(cond.returnType) || cond.returnType.IsAssignableFrom(methodEx.ReturnType))) { return false; } } //The method is a candidate return true; }
public bool TryContruct( StackContext sctx, PValue[] args, out PValue result, out MemberInfo resolvedMember) { var cond = new call_conditions(sctx, args, PCall.Get, "") { IgnoreId = true }; //Get member candidates var candidates = new Stack<MemberInfo>(); foreach (var ctor in _clrType.GetConstructors()) { if (_method_filter(ctor, cond)) candidates.Push(ctor); } resolvedMember = null; if (candidates.Count == 1) resolvedMember = candidates.Peek(); var ret = _try_execute(candidates, cond, null, out result); if (!ret) resolvedMember = null; return ret; }
/// <summary> /// Checks whether the StackContext hack can be applied. /// </summary> /// <param name = "parameters">The parameters array to check.</param> /// <param name = "cond">The call_condition object for the current call.</param> /// <returns>True if the the hack can be applied, otherwise false.</returns> private static bool _sctx_hack(ParameterInfo[] parameters, call_conditions cond) { //StackContext Hack //NOTE: This might be the source of strange problems! //If the one argument is missing and the first formal parameter is a StackContext, //supply the StackContext received in cond.sctx. return ( //There have to be parameters parameters.Length > 0 && //One argument must be missing cond.Args.Length + 1 == parameters.Length && //First parameter must be a StackContext typeof (StackContext).IsAssignableFrom(parameters[0].ParameterType)); }
private static bool _try_execute( Stack<MemberInfo> candidates, call_conditions cond, PValue subject, out PValue ret) { ret = null; object result; while (candidates.Count > 0) { var candidate = candidates.Pop(); switch (candidate.MemberType) { case MemberTypes.Method: case MemberTypes.Constructor: //Try to execute the method var method = (MethodBase) candidate; var parameters = method.GetParameters(); var cargs = new object[parameters.Length]; //The Sctx hack needs to modify the supplied arguments, so we need a copy of the original reference var sargs = cond.Args; if (_sctx_hack(parameters, cond)) { //Add cond.Sctx to the array of arguments sargs = new PValue[sargs.Length + 1]; Array.Copy(cond.Args, 0, sargs, 1, cond.Args.Length); sargs[0] = Object.CreatePValue(cond.Sctx); } for (var i = 0; i < cargs.Length; i++) { var arg = sargs[i]; if (!(arg.IsTypeLocked || arg.IsNull)) //Neither Type-locked nor null { var P = parameters[i].ParameterType; var A = arg.ClrType; if (!(P.Equals(A) || P.IsAssignableFrom(A))) //Is conversion needed? { if (!arg.TryConvertTo(cond.Sctx, P, false, out arg)) //Try to convert goto failed; //can't use break; because of the surrounding for-loop } } cargs[i] = arg.Value; } //All conversions were succesful, ready to call the method if (method is ConstructorInfo) { result = ((ConstructorInfo) method).Invoke(cargs); } else { try { if (subject == null) result = method.Invoke(null, cargs); else result = method.Invoke(subject.Value, cargs); } catch (TargetInvocationException exc) { var innerRt = exc.InnerException as PrexoniteRuntimeException; if (innerRt != null) throw innerRt.InnerException; else throw; } } goto success; failed: //The method cannot be called. Go on to the next candidate break; case MemberTypes.Field: //Do field access var field = (FieldInfo) candidate; if (cond.Call == PCall.Get) if (subject == null) result = field.GetValue(null); else result = field.GetValue(subject.Value); else { var arg = cond.Args[0]; if (!(arg.IsTypeLocked || arg.IsNull)) //Neither Type-locked nor null { var P = field.FieldType; var A = arg.ClrType; if (!(P.Equals(A) || P.IsAssignableFrom(A))) //Is conversion needed? { if (!arg.TryConvertTo(cond.Sctx, P, false, out arg)) //Try to convert break; } } if (subject == null) field.SetValue(null, arg.Value); else field.SetValue(subject.Value, arg.Value); result = null; } goto success; case MemberTypes.Property: //Push accessor method var property = (PropertyInfo) candidate; if (cond.Call == PCall.Get) candidates.Push(property.GetGetMethod()); else candidates.Push(property.GetSetMethod()); break; case MemberTypes.Event: //Push requested method var info = (EventInfo) candidate; if (cond.Directive == "" || Engine.DefaultStringComparer.Compare(cond.Directive, "Raise") == 0) { candidates.Push(info.GetRaiseMethod()); } else if (Engine.DefaultStringComparer.Compare(cond.Directive, "Add") == 0) { candidates.Push(info.GetAddMethod()); } else if (Engine.DefaultStringComparer.Compare(cond.Directive, "Remove") == 0) { candidates.Push(info.GetRemoveMethod()); } break; } } return false; success: if (cond.Call == PCall.Get) { //We'll let the executing engin decide which ptype suits best: ret = cond.Sctx.CreateNativePValue(result); } return true; }
private bool _try_call_conversion_operator( StackContext sctx, PValue[] args, PCall call, string id, Type targetType, out PValue result) { result = null; if (string.IsNullOrEmpty(id)) throw new ArgumentException("id may not be null or empty."); var cond = new call_conditions(sctx, args, call, id) { returnType = targetType }; //Get member candidates var candidates = new Stack<MemberInfo>( _clrType.FindMembers( MemberTypes.Method, //Member types BindingFlags.Static | BindingFlags.Public, //Search domain _member_filter, cond)); //Filter return _try_execute(candidates, cond, null, out result); }
public bool TryStaticCall( StackContext sctx, PValue[] args, PCall call, string id, out PValue result, out MemberInfo resolvedMember) { result = null; resolvedMember = null; if (id == null) id = ""; var cond = new call_conditions(sctx, args, call, id); MemberTypes mtypes; MemberFilter filter; if (id.Length != 0) { filter = _member_filter; if (id.LastIndexOf('\\') == 0) return false; //Default index accessors do not accept calling directives mtypes = MemberTypes.Event | MemberTypes.Field | MemberTypes.Method | MemberTypes.Property; } else { filter = _default_member_filter; mtypes = MemberTypes.Property | MemberTypes.Method; cond.memberRestriction = new List<MemberInfo>(_clrType.GetDefaultMembers()); cond.IgnoreId = true; } //Get member candidates var candidates = new Stack<MemberInfo>( _clrType.FindMembers( mtypes, //Member types BindingFlags.Static | BindingFlags.Public, //Search domain filter, cond)); //Filter if (candidates.Count == 1) resolvedMember = candidates.Peek(); var ret = _try_execute(candidates, cond, null, out result); if (!ret) //Call did not succeed -> member invalid resolvedMember = null; return ret; }
internal bool TryDynamicCall( StackContext sctx, PValue subject, PValue[] args, PCall call, string id, out PValue result, out MemberInfo resolvedMember, bool suppressIObject) { result = null; resolvedMember = null; if (id == null) id = ""; var iobj = subject.Value as IObject; if ((!suppressIObject) && iobj != null && iobj.TryDynamicCall(sctx, args, call, id, out result)) return true; //Special interop members switch (id.ToLowerInvariant()) { case @"\implements": foreach (var arg in args) { Type T; if (arg.Type is ObjectPType && typeof (Type).IsAssignableFrom(((ObjectPType) arg.Type).ClrType)) T = (Type) arg.Value; else T = GetType(sctx, arg.CallToString(sctx)); if (!T.IsAssignableFrom(ClrType)) { result = false; return true; } } result = true; return true; case @"\boxed": result = sctx.CreateNativePValue(subject); return true; } var cond = new call_conditions(sctx, args, call, id); MemberTypes mtypes; MemberFilter filter; if (id.Length != 0) { filter = _member_filter; if (id.LastIndexOf('\\') == 0) return false; //Default index accessors do not accept calling directives mtypes = MemberTypes.Event | MemberTypes.Field | MemberTypes.Method | MemberTypes.Property; } else { filter = _default_member_filter; mtypes = MemberTypes.Property | MemberTypes.Method; cond.memberRestriction = new List<MemberInfo>(_clrType.GetDefaultMembers()); cond.IgnoreId = true; if (subject.Value is Array) { cond.memberRestriction.AddRange( _clrType.FindMembers( MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance, Type.FilterName, cond.Call == PCall.Get ? "GetValue" : "SetValue")); cond.memberRestriction.AddRange( _clrType.FindMembers( MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance, Type.FilterName, cond.Call == PCall.Get ? "Get" : "Set")); } } //Get public member candidates, a stack is used so that newly discovered members // can be examined with priority var candidates = new Stack<MemberInfo>( _clrType.FindMembers( mtypes, //Member types BindingFlags.Instance | BindingFlags.Public, //Search domain filter, cond)); //Filter if (candidates.Count == 1) resolvedMember = candidates.Peek(); var ret = _try_execute(candidates, cond, subject, out result); if (!ret) //Call did not succeed -> member invalid resolvedMember = null; return ret; }