/// /// <summary> /// Determines if it is possible to coerce the given list of arguments /// so a method signature can be matched. /// </summary> /// /// <param name="args">List of arguments to check</param> /// /// <returns> /// True if exactly one argument is of an integral type, false otherwise. /// Idea is to only coerce integral arguments since floating point arguments /// would lose precision when converted to a narrower type and objects don't /// need it due to inheritance (i.e. they will match the method signature without /// it). If there is more than one integral argument, then the chance that the /// wrong overloaded method is called is too great, and so this method returns /// false meaning it can't safely coerce the integral args. If only one is found, /// and a method can't be matched without coercion, then we can safely narrow /// down that one integral arg without worry about matching the wrong method. /// </returns> /// private static bool CanCoerce(List <CseObject> args) { if (args == null) { return(false); } bool foundIntType = false; bool canCoerce = false; for (int i = 0; i < args.Count; i++) { CseObject arg = args[i]; if (LiteralExp.IsIntType(arg)) { if (!foundIntType) { canCoerce = true; foundIntType = true; } else { canCoerce = false; break; } } } return(canCoerce); }
/// /// <summary> /// Converts string parameter containing type into an actual type /// </summary> /// /// <param name="typeData">String containing type</param> /// /// <returns>Found type or null if type is not found</returns> /// public static Type GetType(string typeData) { if (!HasCachedCommonTypes) { CacheCommonTypes(); } LiteralExp.ParseEscSeqs(ref typeData, false); Type returnedType = null; Regex typeRegex = new Regex(@"^[\w][\w\d]*$"); if (typeRegex.IsMatch(typeData)) { bool isFailedtype; if (!cachedTypes.TryGetValue(typeData, out returnedType) && !failedTypes.TryGetValue(typeData, out isFailedtype)) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { foreach (Type type in assembly.GetTypes()) { if (type.Name == typeData) { returnedType = type; cachedTypes[typeData] = returnedType; break; } } if (returnedType != null) { cachedTypes[typeData] = returnedType; break; } } catch (System.Reflection.ReflectionTypeLoadException) { continue; } } } if (returnedType == null) { failedTypes[typeData] = true; } } return(returnedType); }
/// /// <summary> /// Applies numeric negation (i.e. unary minus) to numeric values /// </summary> /// /// <param name="obj">The CseObject with the value to negate</param> /// /// <returns>The CseObject after negation</returns> /// /// <exception cref="CseLogicExceptionType.CANT_NEGATE_NON_NUM" /> /// <exception cref="CseLogicExceptionType.ERROR_NEGATING_VALUE_OF_TYPE" /> /// internal static CseObject Negate(CseObject obj) { CseObject result = (CseObject)obj.Clone(); dynamic value = obj.Value; double numValue; if (value is string) { throw new CseLogicException(CseLogicExceptionType.CANT_NEGATE_NON_NUM, value.ToString()); } else if (!double.TryParse(value.ToString(), out numValue)) { MethodInfo mi = value.GetType().GetMethod(OpOverloadNames.UMINUS); if (null != mi) { result.Value = value.GetType().InvokeMember(OpOverloadNames.UMINUS, OpOverloadNames.Flags, null, CsEval.evalEnvironment, new object[] { value }); return(result); } else { throw new CseLogicException(CseLogicExceptionType.CANT_NEGATE_NON_NUM, value.ToString()); } } numValue *= -1; result.Value = numValue; try { result = CastExp.Parse(CsEval.evalEnvironment, value.GetType().Name, result); } catch { if (value.ToString().ToLower().Contains("e")) { result = LiteralExp.ParseEType(numValue.ToString()); } else if (value.ToString().Contains(".")) { result = LiteralExp.ParseFloatType(numValue.ToString(), null); } else { throw new CseLogicException(CseLogicExceptionType.ERROR_NEGATING_VALUE_OF_TYPE, value.ToString(), value.GetType().Name); } } return(result); }
/// /// <summary> /// Inspects all CseObjects in args and for the literal integral values, it /// converts their type to the most narrow type that can contain their value. /// E.g. if the value is a literal 300 (not the value of an identifier as those /// types aren't changed), then the smallest integral data type that can store /// that would be a short. This increases the chance that the given args will /// match a wider method signature. /// </summary> /// /// <param name="args">Arguments to inspect and convert</param> /// private static void NarrowAllIntTypes(ref List <CseObject> args) { if (args == null) { return; } for (int i = 0; i < args.Count; i++) { CseObject arg = args[i]; if (LiteralExp.IsIntType(arg) && arg.IsLiteral) { args[i] = LiteralExp.NarrowIntType(arg); args[i].CompileTimeType = args[i].Value.GetType(); } } }
/// /// <summary> /// Parses identifiers (fields or properties) /// </summary> /// /// <param name="environment">The environment containing the field or property</param> /// <param name="data">The name of the field or property</param> /// /// <returns>An CseObject containing the value of the identifier or containing null if identifier cannot be found</returns> /// /// <exception cref="CseLogicExceptionType.IDENT_NOT_FOUND" /> /// internal static CseObject Parse(CseObject environment, string data) { if (data[0].Equals('@')) { data = data.Remove(0, 1); } LiteralExp.ParseEscSeqs(ref data, false); CseObject result = null; Type instanceType = TypeExp.GetTypeObj(environment.Value); if (!instanceType.IsEnum) { if (environment == CsEval.EvalEnvironment) { CseObject tempLookup = TempIdentifierExp.Lookup(data); if (tempLookup != null) { return(tempLookup); } } FieldInfo fieldInfo = instanceType.GetField(data, defaultFlags | BindingFlags.GetField); if (fieldInfo != null) { result = new CseObject(fieldInfo.GetValue(environment.Value)); result.CompileTimeType = fieldInfo.FieldType; } else { PropertyInfo propertyInfo = instanceType.GetProperty(data, defaultFlags | BindingFlags.GetProperty); if (propertyInfo != null) { result = new CseObject(propertyInfo.GetValue(environment.Value, null)); result.CompileTimeType = propertyInfo.PropertyType; } else { Type t = TypeExp.GetType(data); if (t != null) { result = new CseObject(t); result.CompileTimeType = t.GetType(); } else { throw new CseLogicException(CseLogicExceptionType.IDENT_NOT_FOUND, data); } } } } else { dynamic resultObj = Enum.Parse(instanceType, data); result = new CseObject(resultObj); result.CompileTimeType = resultObj.GetType(); } return(result); }