/// /// <summary> /// Parses object construction expression (expressions using "new") /// </summary> /// /// <param name="instance">The root object</param> /// <param name="typeName">Name of the type to create</param> /// <param name="constructorParams"> /// CseObject array containing arguments to be sent to the constructor. /// Each CseObject is one argument /// </param> /// /// <returns>CseObject containing the new object</returns> /// /// <exception cref="CseLogicExceptionType.UNKNOWN_TYPE" /> /// internal static CseObject Parse(CseObject instance, string typeName, List <CseObject> constructorParams) { BindingFlags flags = BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; Type typeFound = TypeExp.GetType(typeName); CseObject result = null; if (typeFound != null) { if (constructorParams != null && constructorParams.Count > 0) { object[] objArgs = new object[constructorParams.Count]; for (int i = 0; i < constructorParams.Count; i++) { objArgs[i] = constructorParams[i].Value; } result = new CseObject(Activator.CreateInstance(typeFound, flags, null, objArgs, null)); } else { result = new CseObject(Activator.CreateInstance(typeFound, flags, null, null, null)); } } else { throw new CseLogicException(CseLogicExceptionType.UNKNOWN_TYPE, typeName); } return(result); }
/// /// <summary> /// Adds a temporary identifier of the given type and name and initializes /// it to the given initValue /// </summary> /// /// <param name="type">Type of identifier</param> /// <param name="name">Name of identifier</param> /// <param name="initValue">Initial value of identifer</param> /// public static void AddIdent(Type type, string name, dynamic initValue) { dynamic value = (initValue is CseObject ? initValue.Value : initValue); // TODO: Make CseExceptionType for type assign mismatch if (!TypeExp.TypeAssignMatch(type, value)) { throw new Exception(String.Format("Cannot assign {0} to variable of type {1}", value, type.ToString())); } CseObject ident = new CseObject(value) { CompileTimeType = type, IsLiteral = false, CallMod = CallArgMod.VAL }; /* TODO: Add custom error type and message for duplicate ident names * if (tempIdents.ContainsKey(name)) * throw new CseLogicException(CseLogicExceptionType.??, name); * * TODO: Add keyword (maybe with a prefix) that returns a list of all * currently stored temp vars along with their type and value */ tempIdents.Add(name, ident); }
/// /// <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); }
/// /// <summary> /// Parses array expressions /// </summary> /// /// <param name="rootInstance">Environment where the array is implemented</param> /// <param name="arrayIdent">Name of the array</param> /// <param name="index">Object for the index value</param> /// /// <returns>CseObject containing the array element at the specified index</returns> /// /// <exception cref="CseLogicExceptionType.IDENT_IS_NOT_ARRAY" /> /// <exception cref="CseLogicExceptionType.IDENT_NOT_FOUND" /> /// public static CseObject Parse(CseObject rootInstance, string arrayIdent, CseObject index) { BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; Type rootInstanceType = TypeExp.GetTypeObj(rootInstance.Value); object result = null; FieldInfo fieldInfo = rootInstanceType.GetField(arrayIdent, flags); if (fieldInfo != null) { result = fieldInfo.GetValue(rootInstance.Value); } else { PropertyInfo propertyInfo = rootInstanceType.GetProperty(arrayIdent); if (propertyInfo != null) { result = propertyInfo.GetValue(rootInstance.Value, null); } else { throw new CseLogicException(CseLogicExceptionType.IDENT_NOT_FOUND, arrayIdent); } } IDictionary dictionary = result as IDictionary; Array array = result as Array; if (dictionary != null) { return(new CseObject(dictionary[index.Value])); } else if (array != null) { return(new CseObject(array.GetValue(long.Parse(index.Value.ToString())))); } else { throw new CseLogicException(CseLogicExceptionType.IDENT_IS_NOT_ARRAY, arrayIdent); } }
/// /// <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); }
/// /// <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); } }
/// /// <summary> /// Parses casts /// </summary> /// /// <remarks> /// Can only perform a real cast in certain situations. When it can't it /// tries to mimic a cast using parsing or conversion. /// </remarks> /// /// <param name="instance">The root object</param> /// <param name="typeName">Type to cast to</param> /// <param name="cseData">Expression to cast</param> /// /// <returns>The converted object</returns> /// /// <exception cref="CseLogicExceptionType.CANT_CAST_VALUE_TO_TYPE" /> /// <exception cref="CseLogicExceptionType.OVERFLOW_TRYING_TO_CAST" /> /// // TODO: Check if the generic Cast<T> method would work internal static CseObject Parse(CseObject instance, string typeName, CseObject cseData) { dynamic data = cseData.Value; dynamic castedObj = null; Type dataType = TypeExp.GetTypeObj(data); if (dataType.IsEnum) { switch (typeName.ToLower()) { case "bool": castedObj = (bool)data; break; case "byte": castedObj = (byte)data; break; case "decimal": castedObj = (decimal)data; break; case "double": castedObj = (double)data; break; case "float": castedObj = (float)data; break; case "int": castedObj = (int)data; break; case "int16": castedObj = (Int16)data; break; case "int32": castedObj = (Int32)data; break; case "int64": castedObj = (Int64)data; break; case "long": castedObj = (long)data; break; case "sbyte": castedObj = (sbyte)data; break; case "short": castedObj = (short)data; break; case "single": castedObj = (Single)data; break; case "uint": castedObj = (uint)data; break; case "uint16": castedObj = (UInt16)data; break; case "uint32": castedObj = (UInt32)data; break; case "uint64": castedObj = (UInt64)data; break; case "ulong": castedObj = (ulong)data; break; case "ushort": castedObj = (ushort)data; break; default: castedObj = Enum.Parse(dataType, cseData.Value.ToString()); // instance.Value; break; } } else { switch (typeName.ToLower()) { case "bool": bool boolAttempt; if (bool.TryParse(data.ToString(), out boolAttempt)) { castedObj = boolAttempt; } break; case "byte": byte byteAttempt; if (byte.TryParse(data.ToString(), out byteAttempt)) { castedObj = byteAttempt; } break; case "decimal": decimal decimalAttempt; if (decimal.TryParse(data.ToString(), out decimalAttempt)) { castedObj = decimalAttempt; } break; case "double": double doubleAttempt; if (double.TryParse(data.ToString(), out doubleAttempt)) { castedObj = doubleAttempt; } break; case "float": float floatAttempt; if (float.TryParse(data.ToString(), out floatAttempt)) { castedObj = floatAttempt; } break; case "int": int intAttempt; if (int.TryParse(data.ToString(), out intAttempt)) { castedObj = intAttempt; } break; case "int16": Int16 int16Attempt; if (Int16.TryParse(data.ToString(), out int16Attempt)) { castedObj = int16Attempt; } break; case "int32": Int32 int32Attempt; if (Int32.TryParse(data.ToString(), out int32Attempt)) { castedObj = int32Attempt; } break; case "int64": Int64 int64Attempt; if (Int64.TryParse(data.ToString(), out int64Attempt)) { castedObj = int64Attempt; } break; case "long": long longAttempt; if (long.TryParse(data.ToString(), out longAttempt)) { castedObj = longAttempt; } break; case "sbyte": sbyte sbyteAttempt; if (sbyte.TryParse(data.ToString(), out sbyteAttempt)) { castedObj = sbyteAttempt; } break; case "short": short shortAttempt; if (short.TryParse(data.ToString(), out shortAttempt)) { castedObj = shortAttempt; } break; case "single": Single singleAttempt; if (Single.TryParse(data.ToString(), out singleAttempt)) { castedObj = singleAttempt; } break; case "uint": uint uintAttempt; if (uint.TryParse(data.ToString(), out uintAttempt)) { castedObj = uintAttempt; } break; case "uint16": UInt16 uint16Attempt; if (UInt16.TryParse(data.ToString(), out uint16Attempt)) { castedObj = uint16Attempt; } break; case "uint32": UInt32 uint32Attempt; if (UInt32.TryParse(data.ToString(), out uint32Attempt)) { castedObj = uint32Attempt; } break; case "uint64": UInt64 uint64Attempt; if (UInt64.TryParse(data.ToString(), out uint64Attempt)) { castedObj = uint64Attempt; } break; case "ulong": ulong ulongAttempt; if (ulong.TryParse(data.ToString(), out ulongAttempt)) { castedObj = ulongAttempt; } break; case "ushort": ushort ushortAttempt; if (ushort.TryParse(data.ToString(), out ushortAttempt)) { castedObj = ushortAttempt; } break; } if (castedObj == null) { double dataAsDouble; if (double.TryParse(data.ToString(), out dataAsDouble)) { try { switch (typeName.ToLower()) { case "byte": castedObj = checked ((byte)dataAsDouble); break; case "int": castedObj = checked ((int)dataAsDouble); break; case "int16": castedObj = checked ((Int16)dataAsDouble); break; case "int32": castedObj = checked ((Int32)dataAsDouble); break; case "int64": castedObj = checked ((Int64)dataAsDouble); break; case "long": castedObj = checked ((long)dataAsDouble); break; case "sbyte": castedObj = checked ((sbyte)dataAsDouble); break; case "short": castedObj = checked ((short)dataAsDouble); break; case "single": castedObj = checked ((Single)dataAsDouble); break; case "uint": castedObj = checked ((uint)dataAsDouble); break; case "uint16": castedObj = checked ((UInt16)dataAsDouble); break; case "uint32": castedObj = checked ((UInt32)dataAsDouble); break; case "uint64": castedObj = checked ((UInt64)dataAsDouble); break; case "ulong": castedObj = checked ((ulong)dataAsDouble); break; case "ushort": castedObj = checked ((ushort)dataAsDouble); break; } } catch (OverflowException) { throw new CseLogicException(CseLogicExceptionType.OVERFLOW_TRYING_TO_CAST, data.ToString(), typeName); } } } if (castedObj == null) { try { /* If parsing is not possible, try a conversion */ Type typeToCastTo = TypeExp.GetType(typeName); castedObj = Convert.ChangeType(data, typeToCastTo); } catch { throw new CseLogicException(CseLogicExceptionType.CANT_CAST_VALUE_TO_TYPE, data.ToString(), typeName); } } } return(new CseObject(castedObj) { IsLiteral = cseData.IsLiteral }); //return cseData.Clone(castedObj); }