Used in overloaded and overwritten method resolution
Beispiel #1
0
        ///
        /// <summary>
        ///		Returns the best applicable and invokable member for a given MethResSettings object.
        /// </summary>
        ///
        /// <param name="mrSettings">The object to match when invoking</param>
        ///
        /// <returns>The specific best invokable member that matches the passed MethResSettings object</returns>
        ///
        public static MethResObject GetBestInvocableMember(MethResSettings mrSettings)
        {
            MethResObject mrObj = GetBestMember(mrSettings);

            // check if member is invocable (return it if it is, otherwise return null)
            return(mrObj);
        }
Beispiel #2
0
		///
		/// <summary>
		///		Returns the best matching member for a given MethResSettings object.
		/// </summary>
		/// 
		/// <param name="mrSettings">The object to match when invoking</param>
		/// 
		/// <returns>The specific best member that matches the passed MethResSettings object</returns>
		///
		public static MethResObject GetBestMember(MethResSettings mrSettings) {
			List<MethResObject> mrObjs = GetApplicableMembers(mrSettings);

			if (mrObjs.Count == 1) {
				// TODO: Should we go through steps anyway? Return null if it doesn't pass?
				return mrObjs[0];
			}
			else {
				// do work here

				return new MethResObject();	// <- change this
			}
		}
Beispiel #3
0
        ///
        /// <summary>
        ///		Returns all members that match the name (candidates) of the given MethResSettings object.
        /// </summary>
        ///
        /// <param name="mrSettings">The object to match when invoking</param>
        ///
        /// <returns>The list of candidate members, as defined in the C# specification, that matches the passed
        /// MethResSettings object</returns>
        ///
        public static List <MethResObject> GetCandidateMembers(MethResSettings mrSettings)
        {
            // Find members that match on name
            Type t = TypeExp.GetTypeObj(mrSettings.Env);
            List <MethResObject> matchMeths = GetMethodInfos(t, mrSettings);

            // Traverse through class hierarchy
            while (matchMeths.Count == 0 && t != typeof(object))
            {
                t          = t.BaseType;
                matchMeths = GetMethodInfos(t, mrSettings);
            }

            return(matchMeths);
        }
Beispiel #4
0
        ///
        /// <summary>
        ///		Returns the best matching member for a given MethResSettings object.
        /// </summary>
        ///
        /// <param name="mrSettings">The object to match when invoking</param>
        ///
        /// <returns>The specific best member that matches the passed MethResSettings object</returns>
        ///
        public static MethResObject GetBestMember(MethResSettings mrSettings)
        {
            List <MethResObject> mrObjs = GetApplicableMembers(mrSettings);

            if (mrObjs.Count == 1)
            {
                // TODO: Should we go through steps anyway? Return null if it doesn't pass?
                return(mrObjs[0]);
            }
            else
            {
                // do work here

                return(new MethResObject());                    // <- change this
            }
        }
Beispiel #5
0
        ///
        /// <summary>
        ///		Returns a list of MethResObject objects, within the given environment and MethResSettings object, according to the C#
        ///		specification.
        /// </summary>
        ///
        /// <param name="env">The environment to use when locating the desired MethResObject objects.</param>
        /// <param name="mrSettings">The object to match when invoking</param>
        ///
        /// <returns>The list of MethResObjects which match the given MethResSettings object and environment.</returns>
        ///
        public static List <MethResObject> GetMethodInfos(Type env, MethResSettings mrSettings)
        {
            List <MethResObject> result = new List <MethResObject>();

            foreach (MethodInfo mi in env.GetMethods(findFlags))
            {
                Func <bool> IsVirtual = () => (mi.Attributes & MethodAttributes.Virtual) != 0;
                Func <bool> HasVTable = () => (mi.Attributes & MethodAttributes.VtableLayoutMask) != 0;

                if (mi.Name == mrSettings.Name && (mrSettings.IsExtInvocation || !IsVirtual() || HasVTable()))
                {
                    result.Add(new MethResObject(mi, null, mrSettings.Args));
                }
            }

            return(result);
        }
Beispiel #6
0
		///
		/// <summary>
		///		Parses method calls
		/// </summary>
		/// 
		/// <param name="environment">The environment containing the method</param>
		/// <param name="methName">Name of the method</param>
		/// <param name="args">CseObject array containing arguments to be sent to the method. Each CseObject is one argument</param>
		/// 
		/// <returns>CseObject containing the return result of the method call or CseObject containing null if method is void</returns>
		/// 
		/// <exception cref="CseLogicExceptionType.METHOD_CALL_AMBIGUOUS" />
		/// <exception cref="CseLogicExceptionType.METHOD_CANT_IMPLICITLY_COERCE_ARGS" />
		/// <exception cref="CseLogicExceptionType.METHOD_DOESNT_EXIST" />
		/// <exception cref="CseLogicExceptionType.METHOD_EXISTS_BUT_CANT_BE_INVOKED" />
		///
		public static CseObject Parse(CseObject environment, string methName, List<CseObject> args) {
			MethResSettings mrSettings = new MethResSettings() {
				Args = (args == null ? new CseObject[] { } : args.ToArray()),
				Env = environment.Value,
				Name = methName
			};
			List<MethResObject> appMeths = MethRes.GetApplicableMembers(mrSettings);

			if (appMeths.Count == 0) {
				mrSettings.IsExtInvocation = true;
				appMeths = MethRes.GetApplicableMembers(mrSettings);
			}

			MethodInfo mi = null;
			Type envType = TypeExp.GetTypeObj(environment.Value);

			try {
				switch (appMeths.Count) {
					// No methods exist with that name
					case 0:
						// TODO: doesn't exist OR no applicable methods can be called
						throw new CseLogicException(CseLogicExceptionType.METHOD_DOESNT_EXIST, methName);

					// Only 1 method exists with that name, so try to do what's necessary to coerce args (if they exist)
					// to match its signature.
					case 1:
						MethResObject mrObj = appMeths[0];

						if (args != null) {
							for (int i = 0; i < args.Count; i++) {
								try {
									args[i] = CastExp.Parse(environment, mrObj.MethInfo.GetParameters()[i].ParameterType.Name, args[i]);
								}
								catch (CseLogicException) {
									// f**k it, continue
								}
							}
						}
						//NarrowAllIntTypes(ref args);

						mi = mrObj.MethInfo;
						break;

					// Method is overloaded.
					// Idea is to simulate C#'s best match algorithm for finding the most appropriate method to call
					// and if still unsure, throw exception so user can use casting for further clarification.
					default:
						Type[] types = GetTypeArray(args);

						mi = envType.GetMethod(methName, findFlags | BindingFlags.ExactBinding, null, types, null);

						if (mi != null)
							break;

						if (CanCoerce(args)) {
							NarrowAllIntTypes(ref args);
							types = GetTypeArray(args);
						}

						MethodInfo tryMeth = envType.GetMethod(methName, findFlags, null, types, null);
						foreach (MethResObject m in appMeths) {
							if (m.MethInfo == tryMeth) {
								mi = tryMeth;
								break;
							}
						}

						if (mi != null)
							break;

						// TODO: Attempt to coerce args to formal param types of overloaded methods



						if (mi == null)
							throw new CseLogicException(CseLogicExceptionType.METHOD_CALL_AMBIGUOUS, methName);

						break;
				}
			}
			catch (AmbiguousMatchException) {
				throw new CseLogicException(CseLogicExceptionType.METHOD_CALL_AMBIGUOUS, methName);
			}
			catch (CseLogicException) {
				throw;
			}
			catch {
				throw new CseLogicException(CseLogicExceptionType.METHOD_EXISTS_BUT_CANT_BE_INVOKED, methName);
			}

			if (mi == null) {
				throw new CseLogicException(CseLogicExceptionType.METHOD_EXISTS_BUT_CANT_BE_INVOKED, methName);
			}
			else {
				dynamic result = mi.Invoke(environment.Value, GetObjArgs(args));

				CseObject xo = new CseObject(result);
				xo.CompileTimeType = mi.ReturnType;

				if (args != null) {
					foreach (CseObject arg in args) {
						if (arg.CallMod != CallArgMod.VAL) {
							AssignExp.Parse(arg.EnvChain, arg.EnvNames, arg.EnvIndices, arg.Value);
						}
					}
				}

				return xo;
			}
		}
Beispiel #7
0
        ///
        /// <summary>
        ///		Parses method calls
        /// </summary>
        ///
        /// <param name="environment">The environment containing the method</param>
        /// <param name="methName">Name of the method</param>
        /// <param name="args">CseObject array containing arguments to be sent to the method. Each CseObject is one argument</param>
        ///
        /// <returns>CseObject containing the return result of the method call or CseObject containing null if method is void</returns>
        ///
        /// <exception cref="CseLogicExceptionType.METHOD_CALL_AMBIGUOUS" />
        /// <exception cref="CseLogicExceptionType.METHOD_CANT_IMPLICITLY_COERCE_ARGS" />
        /// <exception cref="CseLogicExceptionType.METHOD_DOESNT_EXIST" />
        /// <exception cref="CseLogicExceptionType.METHOD_EXISTS_BUT_CANT_BE_INVOKED" />
        ///
        public static CseObject Parse(CseObject environment, string methName, List <CseObject> args)
        {
            MethResSettings mrSettings = new MethResSettings()
            {
                Args = (args == null ? new CseObject[] { } : args.ToArray()),
                Env  = environment.Value,
                Name = methName
            };
            List <MethResObject> appMeths = MethRes.GetApplicableMembers(mrSettings);

            if (appMeths.Count == 0)
            {
                mrSettings.IsExtInvocation = true;
                appMeths = MethRes.GetApplicableMembers(mrSettings);
            }

            MethodInfo mi      = null;
            Type       envType = TypeExp.GetTypeObj(environment.Value);

            try {
                switch (appMeths.Count)
                {
                // No methods exist with that name
                case 0:
                    // TODO: doesn't exist OR no applicable methods can be called
                    throw new CseLogicException(CseLogicExceptionType.METHOD_DOESNT_EXIST, methName);

                // Only 1 method exists with that name, so try to do what's necessary to coerce args (if they exist)
                // to match its signature.
                case 1:
                    MethResObject mrObj = appMeths[0];

                    if (args != null)
                    {
                        for (int i = 0; i < args.Count; i++)
                        {
                            try {
                                args[i] = CastExp.Parse(environment, mrObj.MethInfo.GetParameters()[i].ParameterType.Name, args[i]);
                            }
                            catch (CseLogicException) {
                                // f**k it, continue
                            }
                        }
                    }
                    //NarrowAllIntTypes(ref args);

                    mi = mrObj.MethInfo;
                    break;

                // Method is overloaded.
                // Idea is to simulate C#'s best match algorithm for finding the most appropriate method to call
                // and if still unsure, throw exception so user can use casting for further clarification.
                default:
                    Type[] types = GetTypeArray(args);

                    mi = envType.GetMethod(methName, findFlags | BindingFlags.ExactBinding, null, types, null);

                    if (mi != null)
                    {
                        break;
                    }

                    if (CanCoerce(args))
                    {
                        NarrowAllIntTypes(ref args);
                        types = GetTypeArray(args);
                    }

                    MethodInfo tryMeth = envType.GetMethod(methName, findFlags, null, types, null);
                    foreach (MethResObject m in appMeths)
                    {
                        if (m.MethInfo == tryMeth)
                        {
                            mi = tryMeth;
                            break;
                        }
                    }

                    if (mi != null)
                    {
                        break;
                    }

                    // TODO: Attempt to coerce args to formal param types of overloaded methods



                    if (mi == null)
                    {
                        throw new CseLogicException(CseLogicExceptionType.METHOD_CALL_AMBIGUOUS, methName);
                    }

                    break;
                }
            }
            catch (AmbiguousMatchException) {
                throw new CseLogicException(CseLogicExceptionType.METHOD_CALL_AMBIGUOUS, methName);
            }
            catch (CseLogicException) {
                throw;
            }
            catch {
                throw new CseLogicException(CseLogicExceptionType.METHOD_EXISTS_BUT_CANT_BE_INVOKED, methName);
            }

            if (mi == null)
            {
                throw new CseLogicException(CseLogicExceptionType.METHOD_EXISTS_BUT_CANT_BE_INVOKED, methName);
            }
            else
            {
                dynamic result = mi.Invoke(environment.Value, GetObjArgs(args));

                CseObject xo = new CseObject(result);
                xo.CompileTimeType = mi.ReturnType;

                if (args != null)
                {
                    foreach (CseObject arg in args)
                    {
                        if (arg.CallMod != CallArgMod.VAL)
                        {
                            AssignExp.Parse(arg.EnvChain, arg.EnvNames, arg.EnvIndices, arg.Value);
                        }
                    }
                }

                return(xo);
            }
        }
Beispiel #8
0
		///
		/// <summary>
		///		Returns the best applicable and invokable member for a given MethResSettings object.
		/// </summary>
		/// 
		/// <param name="mrSettings">The object to match when invoking</param>
		/// 
		/// <returns>The specific best invokable member that matches the passed MethResSettings object</returns>
		/// 
		public static MethResObject GetBestInvocableMember(MethResSettings mrSettings) {
			MethResObject mrObj = GetBestMember(mrSettings);

			// check if member is invocable (return it if it is, otherwise return null)
			return mrObj;
		}
Beispiel #9
0
		///
		/// <summary>
		///		Returns a list of MethResObject objects, within the given environment and MethResSettings object, according to the C# 
		///		specification.
		/// </summary>
		/// 
		/// <param name="env">The environment to use when locating the desired MethResObject objects.</param>
		/// <param name="mrSettings">The object to match when invoking</param>
		/// 
		/// <returns>The list of MethResObjects which match the given MethResSettings object and environment.</returns>
		///
		public static List<MethResObject> GetMethodInfos(Type env, MethResSettings mrSettings) {
			List<MethResObject> result = new List<MethResObject>();

			foreach (MethodInfo mi in env.GetMethods(findFlags)) {
				Func<bool> IsVirtual = () => (mi.Attributes & MethodAttributes.Virtual) != 0;
				Func<bool> HasVTable = () => (mi.Attributes & MethodAttributes.VtableLayoutMask) != 0;

				if (mi.Name == mrSettings.Name && (mrSettings.IsExtInvocation || !IsVirtual() || HasVTable()))
					result.Add(new MethResObject(mi, null, mrSettings.Args));
			}

			return result;
		}
Beispiel #10
0
		///
		/// <summary>
		///		Returns all members that match the name (candidates) of the given MethResSettings object.
		/// </summary>
		/// 
		/// <param name="mrSettings">The object to match when invoking</param>
		/// 
		/// <returns>The list of candidate members, as defined in the C# specification, that matches the passed 
		/// MethResSettings object</returns>
		///
		public static List<MethResObject> GetCandidateMembers(MethResSettings mrSettings) {
			// Find members that match on name
			Type t = TypeExp.GetTypeObj(mrSettings.Env);
			List<MethResObject> matchMeths = GetMethodInfos(t, mrSettings);

			// Traverse through class hierarchy
			while (matchMeths.Count == 0 && t != typeof(object)) {
				t = t.BaseType;
				matchMeths = GetMethodInfos(t, mrSettings);
			}

			return matchMeths;
		}
Beispiel #11
0
		///
		/// <summary>
		///		Returns all matching members, according to the C# specification, for a given MethResSettings object.
		/// </summary>
		/// 
		/// <param name="mrSettings">The object to match when invoking</param>
		/// 
		/// <returns>The list of applicable members that match the passed MethResSettings object</returns>
		///
		public static List<MethResObject> GetApplicableMembers(MethResSettings mrSettings) {
			List<MethResObject> mrObjs = GetCandidateMembers(mrSettings);

			//if (mrObjs.Count == 1) {
			//   // TODO: Should we go through steps anyway? Return null if it doesn't pass?
			//   return mrObjs;
			//}
			//else {
			// paramater matching && ref C# lang spec section 7.5.1.1
			List<MethResObject> appMembers = new List<MethResObject>();

			// match each param with an arg. 
			List<CallArgMod> paramMods;
			foreach (MethResObject mrObj in mrObjs) {
				bool isMatch = true;
				paramMods = new List<CallArgMod>();
				int argCount = 0;
				foreach (ParameterInfo pInfo in mrObj.MethInfo.GetParameters()) {
					bool haveArg = argCount < mrSettings.Args.Length;

					if (pInfo.IsOut || pInfo.ParameterType.IsByRef) {
						if (!haveArg) {
							isMatch = false;
						}
						else if (pInfo.IsOut) {
							if (mrSettings.Args[argCount].CallMod != CallArgMod.OUT) {
								isMatch = false;
							}
						}
						else if (pInfo.ParameterType.IsByRef) {
							if (mrSettings.Args[argCount].CallMod != CallArgMod.REF) {
								isMatch = false;
							}
						}

						// Step 4 (technically)
						// Check types if either are a ref type. Must match exactly
						String argTypeStr   = mrSettings.Args[argCount].Value.GetType().FullName;
						Type paramType      = mrObj.MethInfo.GetParameters()[argCount].ParameterType;
						String paramTypeStr = paramType.ToString().Substring(0, paramType.ToString().Length - 1);

						if (argTypeStr != paramTypeStr) {
							isMatch = false;
						}

					}
					else {
						if (pInfo.IsOptional) {
							// If an argument for this parameter position was specified, check its type
							if (haveArg && !CanConvertType(mrSettings.Args[argCount], pInfo.ParameterType)) {
								isMatch = false;
							}
						}
						else if (pInfo.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0) { // Check ParamArray arguments
							// TODO: set OnlyAppInExpForm here
							for (int j = pInfo.Position; j < mrSettings.Args.Length; j++) {
								if (!CanConvertType(mrSettings.Args[j], pInfo.ParameterType.GetElementType())) {
									isMatch = false;
								}
								argCount++;
							}
							break;
						}
						else { // Checking non-optional, non-ParamArray arguments
							if (!haveArg || !CanConvertType(mrSettings.Args[argCount], pInfo.ParameterType)) {
								isMatch = false;
							}
						}
					}

					if (!isMatch) {
						break;
					}

					argCount++;
				}

				if (isMatch && argCount < mrSettings.Args.Length)
					isMatch = false;

				if (isMatch)
					appMembers.Add(mrObj);
			}

			return appMembers;
			//}
		}
Beispiel #12
0
        ///
        /// <summary>
        ///		Returns all matching members, according to the C# specification, for a given MethResSettings object.
        /// </summary>
        ///
        /// <param name="mrSettings">The object to match when invoking</param>
        ///
        /// <returns>The list of applicable members that match the passed MethResSettings object</returns>
        ///
        public static List <MethResObject> GetApplicableMembers(MethResSettings mrSettings)
        {
            List <MethResObject> mrObjs = GetCandidateMembers(mrSettings);

            //if (mrObjs.Count == 1) {
            //   // TODO: Should we go through steps anyway? Return null if it doesn't pass?
            //   return mrObjs;
            //}
            //else {
            // paramater matching && ref C# lang spec section 7.5.1.1
            List <MethResObject> appMembers = new List <MethResObject>();

            // match each param with an arg.
            List <CallArgMod> paramMods;

            foreach (MethResObject mrObj in mrObjs)
            {
                bool isMatch = true;
                paramMods = new List <CallArgMod>();
                int argCount = 0;
                foreach (ParameterInfo pInfo in mrObj.MethInfo.GetParameters())
                {
                    bool haveArg = argCount < mrSettings.Args.Length;

                    if (pInfo.IsOut || pInfo.ParameterType.IsByRef)
                    {
                        if (!haveArg)
                        {
                            isMatch = false;
                        }
                        else if (pInfo.IsOut)
                        {
                            if (mrSettings.Args[argCount].CallMod != CallArgMod.OUT)
                            {
                                isMatch = false;
                            }
                        }
                        else if (pInfo.ParameterType.IsByRef)
                        {
                            if (mrSettings.Args[argCount].CallMod != CallArgMod.REF)
                            {
                                isMatch = false;
                            }
                        }

                        // Step 4 (technically)
                        // Check types if either are a ref type. Must match exactly
                        String argTypeStr   = mrSettings.Args[argCount].Value.GetType().FullName;
                        Type   paramType    = mrObj.MethInfo.GetParameters()[argCount].ParameterType;
                        String paramTypeStr = paramType.ToString().Substring(0, paramType.ToString().Length - 1);

                        if (argTypeStr != paramTypeStr)
                        {
                            isMatch = false;
                        }
                    }
                    else
                    {
                        if (pInfo.IsOptional)
                        {
                            // If an argument for this parameter position was specified, check its type
                            if (haveArg && !CanConvertType(mrSettings.Args[argCount], pInfo.ParameterType))
                            {
                                isMatch = false;
                            }
                        }
                        else if (pInfo.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0)                           // Check ParamArray arguments
                        // TODO: set OnlyAppInExpForm here
                        {
                            for (int j = pInfo.Position; j < mrSettings.Args.Length; j++)
                            {
                                if (!CanConvertType(mrSettings.Args[j], pInfo.ParameterType.GetElementType()))
                                {
                                    isMatch = false;
                                }
                                argCount++;
                            }
                            break;
                        }
                        else                           // Checking non-optional, non-ParamArray arguments
                        {
                            if (!haveArg || !CanConvertType(mrSettings.Args[argCount], pInfo.ParameterType))
                            {
                                isMatch = false;
                            }
                        }
                    }

                    if (!isMatch)
                    {
                        break;
                    }

                    argCount++;
                }

                if (isMatch && argCount < mrSettings.Args.Length)
                {
                    isMatch = false;
                }

                if (isMatch)
                {
                    appMembers.Add(mrObj);
                }
            }

            return(appMembers);
            //}
        }