using Flee.InternalTypes; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Text; namespace Convention.RScript.Variable { namespace Attr { [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public sealed class MethodAttribute : Attribute { } [AttributeUsage(AttributeTargets.Enum, Inherited = true, AllowMultiple = false)] public sealed class EnumAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] public sealed class DefaultAttribute : Attribute { public string defaultScript; public DefaultAttribute(string defaultScript) { this.defaultScript = defaultScript; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] public sealed class DescriptionAttribute : Attribute { public string description; public DescriptionAttribute(string description) { this.description = description; } } } public abstract class RScriptInjectVariableGenerater { public string RScriptString { get; private set; } public abstract string GetFilename(Type currentType); protected abstract string WritePageHead(Type currentType); #region Enum protected abstract string WriteEnumHead(Type currentEnum); protected abstract string WriteEnumBodyEnter(Type currentType); protected abstract string WriteEnumName(string enumName); protected abstract string WriteEnumBodyExit(Type currentType); protected abstract string WriteEnumTail(Type currentType); #endregion #region Class protected abstract string WriteClassHead(Type currentType); protected abstract string WriteClassBodyEnter(Type currentType); protected abstract string WriteClassMethod(Type returnType, string methodName, string[] parameterNames, Type[] parameterTypes); protected abstract string WriteClassBodyExit(Type currentType); protected abstract string WriteClassTail(Type currentType); #endregion protected abstract string WritePageEnd(Type currentType); /// /// 生成targetType类型的实体 /// /// public delegate object Generater(); public delegate void Destorier(object o); private readonly Generater MyGenerater; private readonly Destorier MyDestorier; private readonly HashSet GenerateObjects = new(); public readonly static Dictionary AllRScriptInjectVariables = new(); public readonly Type targetType; public readonly string name; public readonly string scriptIndicator; public readonly string defaultScript; public readonly string description; public object Generate() { return MyGenerater(); } public RScriptInjectVariableGenerater(Type targetType, [MaybeNull] Generater generater, [MaybeNull] Destorier destorier, string name) { if (AllRScriptInjectVariables.TryGetValue(name, out var exist_var)) { throw new InvalidOperationException($"{name} is been used"); } this.targetType = targetType; this.MyGenerater = generater; this.MyDestorier = destorier; this.name = name; var defaultAttr = targetType.GetCustomAttribute(); this.defaultScript = defaultAttr?.defaultScript ?? ""; var descriptionAttr = targetType.GetCustomAttribute(); this.description = descriptionAttr?.description ?? ""; StringBuilder builder = new(); builder.AppendLine(this.WritePageHead(targetType)); if (targetType.IsEnum) { // 绘制枚举 builder.AppendLine(this.WriteEnumHead(targetType)); builder.AppendLine(this.WriteEnumBodyEnter(targetType)); foreach (var enumName in targetType.GetEnumNames()) { builder.AppendLine(this.WriteEnumName(enumName)); } builder.AppendLine(this.WriteEnumBodyExit(targetType)); builder.AppendLine(this.WriteEnumTail(targetType)); } else { builder.AppendLine(this.WriteClassHead(targetType)); builder.AppendLine(this.WriteClassBodyEnter(targetType)); // 绘制枚举 { var scriptEnums = from enumItem in targetType.GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Public) where enumItem.GetCustomAttribute() != null select enumItem; foreach (var enumItem in scriptEnums) { var attr = enumItem.GetCustomAttribute(); this.WriteEnumHead(targetType); this.WriteEnumBodyEnter(targetType); foreach (var enumName in enumItem.GetEnumNames()) { this.WriteEnumName(enumName); } this.WriteEnumBodyExit(targetType); this.WriteEnumTail(targetType); } } // 绘制方法 { var scriptMethods = from method in targetType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly) where method.GetCustomAttribute() != null select method; foreach (var method in scriptMethods) { var attr = method.GetCustomAttribute(); var returnType = method.ReturnType; var methodName = method.Name; var parameters = method.GetParameters(); var parameterNames = from item in parameters select item.Name; var parameterTypes = from item in parameters select item.ParameterType; builder.AppendLine(this.WriteClassMethod(returnType, methodName, parameterNames.ToArray(), parameterTypes.ToArray())); } } builder.AppendLine(this.WriteClassBodyExit(targetType)); builder.AppendLine(this.WriteClassTail(targetType)); } builder.AppendLine(this.WritePageEnd(targetType)); this.scriptIndicator = builder.ToString(); } public void Register() { AllRScriptInjectVariables.Add(name, this); } public bool Unregister() { if (MyDestorier != null) foreach (var item in GenerateObjects) { MyDestorier(item); } this.GenerateObjects.Clear(); return AllRScriptInjectVariables.Remove(name); } public class EnumGetter { public Type enumType; public EnumGetter(Type enumType) { this.enumType = enumType; } public object Get(string name) { return Enum.Parse(enumType, name); } } public static object GenerateRScriptVariable(string name) { if (AllRScriptInjectVariables.TryGetValue(name, out var variable)) { if (variable.targetType.IsEnum) { if (variable.MyGenerater != null) { var result = variable.Generate(); if (result.GetType().IsSubclassOf(variable.targetType) || result.GetType() == variable.targetType) { variable.GenerateObjects.Add(result); return result; } else throw new InvalidOperationException($"{name} target is not sub-class of it's target type"); } else { return variable.targetType; } } else { if (variable.MyGenerater != null) { var result = variable.Generate(); if (result.GetType().IsSubclassOf(variable.targetType) || result.GetType() == variable.targetType) { variable.GenerateObjects.Add(result); return result; } else throw new InvalidOperationException($"{name} target is not sub-class of it's target type"); } } } throw new InvalidOperationException($"{name} target is not exist or abstract"); } public static string DestoryRScriptVariable(object o) { if (o == null) return string.Empty; foreach (var (name,variable) in AllRScriptInjectVariables) { variable.GenerateObjects.RemoveWhere(x => x == null); if(variable.GenerateObjects.Remove(o)) { variable.MyDestorier(o); return variable.name; } } return string.Empty; } } public static class RScriptVariableGenerater { public static object New(string name) { return RScriptInjectVariableGenerater.GenerateRScriptVariable(name); } public static string Delete(object o) { return RScriptInjectVariableGenerater.DestoryRScriptVariable(o); } } }