using System.Reflection; using System.Text; using System.Text.RegularExpressions; namespace RobotNet10.ScriptEngine.Shared; public static partial class ScriptHelpers { public static string ToString(ParameterInfo parameter) { var modifier = ""; if (parameter.IsDefined(typeof(ParamArrayAttribute), false)) modifier = "params "; else if (parameter.IsIn && parameter.ParameterType.IsByRef && !parameter.IsOut) modifier = "in "; else if (parameter.IsOut) modifier = "out "; else if (parameter.ParameterType.IsByRef) modifier = "ref "; var typeString = ScriptHelpers.ToString( parameter.ParameterType.IsByRef ? parameter.ParameterType.GetElementType()! : parameter.ParameterType ); var defaultValue = ""; if (parameter.HasDefaultValue) { if (parameter.DefaultValue != null) { if (parameter.ParameterType.IsEnum) { defaultValue = $" = {ScriptHelpers.ToString(parameter.ParameterType)}.{parameter.DefaultValue}"; } else if (parameter.DefaultValue is string) { defaultValue = $" = \"{parameter.DefaultValue}\""; } else if (parameter.DefaultValue is bool b) { defaultValue = $" = {b.ToString().ToLower()}"; } else { defaultValue = $" = {parameter.DefaultValue}"; } } else { defaultValue = " = null"; } } return $"{modifier}{typeString} {parameter.Name}{defaultValue}"; } public static string ToString(Type type) { if (type == typeof(void)) return "void"; if (type.IsGenericType) { var genericTypeName = type.GetGenericTypeDefinition().FullName; if (genericTypeName == null) return type.Name; var backtickIndex = genericTypeName.IndexOf('`'); if (backtickIndex > 0) genericTypeName = genericTypeName[..backtickIndex]; var genericArgs = type.GetGenericArguments(); var argsString = string.Join(", ", genericArgs.Select(ToString)); return $"{genericTypeName}<{argsString}>"; } return type.FullName ?? type.Name; } public static Type? ResolveTypeFromString(string typeString) { typeString = typeString.Trim(); // Handle array types (e.g., System.Int32[], string[], List[]) if (typeString.EndsWith("[]")) { var elementTypeString = typeString[..^2].Trim(); var elementType = ResolveTypeFromString(elementTypeString); return elementType?.MakeArrayType(); } // Trường hợp không phải generic if (!typeString.Contains('<')) { return FindType(typeString); } // Tách phần generic var match = GenericTypeRegex.Match(typeString); if (!match.Success) return null; var genericTypeName = match.Groups["raw"].Value; var genericArgsString = match.Groups["args"].Value; // Phân tách các generic argument (xử lý nested generics) var genericArgs = SplitGenericArguments(genericArgsString); var genericType = FindType(genericTypeName + "`" + genericArgs.Count); if (genericType == null) return null; var resolvedArgs = genericArgs.Select(ResolveTypeFromString).ToArray(); if (resolvedArgs.Any(t => t == null)) return null; return genericType.MakeGenericType(resolvedArgs!); } public static bool ResolveValueFromString(string valueStr, Type type, out object? value) { // Check if type is in MissionParameterTypes if (!SupportedTypes.Values.Contains(type)) { value = null; return false; } // Convert string to the corresponding type if (type == typeof(string)) { value = valueStr; return true; } if (type.IsEnum) { value = Enum.Parse(type, valueStr, ignoreCase: true); return true; } // Handle nullable types var underlyingType = Nullable.GetUnderlyingType(type); if (underlyingType != null) { value = null; return false; } value = Convert.ChangeType(valueStr, type); if (value is null) { return false; } else { return true; } } private static List SplitGenericArguments(string input) { var args = new List(); var sb = new StringBuilder(); int depth = 0; foreach (char c in input) { if (c == ',' && depth == 0) { args.Add(sb.ToString().Trim()); sb.Clear(); } else { if (c == '<') depth++; else if (c == '>') depth--; sb.Append(c); } } if (sb.Length > 0) { args.Add(sb.ToString().Trim()); } return args; } public static Type? FindType(string typeName) { if (SupportedTypes.TryGetValue(typeName, out var systemType)) return systemType; return AppDomain.CurrentDomain .GetAssemblies() .Select(a => a.GetType(typeName, false)) .FirstOrDefault(t => t != null); } public static readonly IReadOnlyDictionary SupportedTypes = new Dictionary() { ["bool"] = typeof(bool), ["byte"] = typeof(byte), ["sbyte"] = typeof(sbyte), ["short"] = typeof(short), ["ushort"] = typeof(ushort), ["int"] = typeof(int), ["uint"] = typeof(uint), ["long"] = typeof(long), ["ulong"] = typeof(ulong), ["double"] = typeof(double), ["float"] = typeof(float), ["double"] = typeof(double), ["char"] = typeof(char), ["string"] = typeof(string), ["object"] = typeof(object), }; private static readonly Regex GenericTypeRegex = CreateGenericTypeRegex(); [GeneratedRegex(@"^(?[^<]+)<(?.+)>$")] private static partial Regex CreateGenericTypeRegex(); }