Files
BQP/srcs/RobotNet10/Shared/RobotNet10.ScriptEngine.Shared/ScriptHelpers.cs
2026-07-13 09:25:40 +07:00

225 lines
6.8 KiB
C#

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<int>[])
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<string> SplitGenericArguments(string input)
{
var args = new List<string>();
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<string, Type> SupportedTypes = new Dictionary<string, Type>()
{
["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(@"^(?<raw>[^<]+)<(?<args>.+)>$")]
private static partial Regex CreateGenericTypeRegex();
}