diff --git a/Parser/ExpressionParser.cs b/Parser/ExpressionParser.cs index fdbe36f..393f390 100644 --- a/Parser/ExpressionParser.cs +++ b/Parser/ExpressionParser.cs @@ -95,6 +95,8 @@ namespace Convention.RScript.Parser public ExpressionParser(ExpressionContext context) { this.context = context; + // 默认启用未定义标识符作为字符串的功能 + this.context.Options.UndefinedIdentifiersAsStrings = true; } private readonly Dictionary CompileGenericExpressionTypen = new(); diff --git a/PublicTypes/InjectVariable/CStyle.cs b/PublicTypes/InjectVariable/CStyle.cs index 31142b9..ac35096 100644 --- a/PublicTypes/InjectVariable/CStyle.cs +++ b/PublicTypes/InjectVariable/CStyle.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace Convention.RScript.Variable.CStyle { - public class RScriptVariableGenerater : RScriptInjectVariableGenerater + public class CScriptRScriptVariableGenerater : RScriptInjectVariableGenerater { public static string GetTypename(Type type) { @@ -15,16 +15,25 @@ namespace Convention.RScript.Variable.CStyle return name; } - private int layer = 0; - private string Prefix => new('\t', layer); + private int m_layer = 0; + private int layer + { + get=>m_layer; + set + { + m_layer = value; + Prefix = new('\t', layer); + } + } + private string Prefix = ""; - public RScriptVariableGenerater(Type targetType, [MaybeNull] Generater generater, string name) : base(targetType, generater, name) + public CScriptRScriptVariableGenerater(Type targetType, Generater generater, Destorier destorier, string name) : base(targetType, generater, destorier, name) { } protected override string WriteClassBodyEnter(Type currentType) { - string result = $"{Prefix}{"{public:"}"; + string result = $"{Prefix}{"{"}\n{Prefix}public:"; layer++; return result; } @@ -32,21 +41,21 @@ namespace Convention.RScript.Variable.CStyle protected override string WriteClassBodyExit(Type currentType) { layer--; - return $"{Prefix}{"{"}"; + return $"{Prefix}{"};"}"; } protected override string WriteClassHead(Type currentType) { + string description = string.IsNullOrEmpty(this.description) ? "" : string.Join("", from item in this.description.Split('\n') where string.IsNullOrEmpty(item) == false select $"{Prefix}{item}\n"); string suffix = currentType.BaseType == typeof(object) ? string.Empty : $" : public {GetTypename(currentType.BaseType)}"; - string result = $"{Prefix}class {GetTypename(currentType)}{suffix}"; - layer++; + string result = $"{Prefix}\\*{description}*\\\n{Prefix}{Prefix}class {GetTypename(currentType)}{suffix}"; return result; } protected override string WriteClassMethod(Type returnType, string methodName, string[] parameterNames, Type[] parameterTypes) { List parameters = new(); - for(int i=0,e=parameterNames.Length;i public delegate object Generater(); - private Generater MyGenerater; + 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(); @@ -75,77 +90,87 @@ namespace Convention.RScript.Variable 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, string name) + public RScriptInjectVariableGenerater(Type targetType, [MaybeNull] Generater generater, [MaybeNull] Destorier destorier, string name) { if (AllRScriptInjectVariables.TryGetValue(name, out var exist_var)) { - if (exist_var.MyGenerater != generater || exist_var.targetType != targetType) - { - throw new InvalidOperationException($"{name} is been used"); - } - this.targetType = exist_var.targetType; - this.name = exist_var.name; - this.scriptIndicator = exist_var.scriptIndicator; - this.defaultScript = exist_var.defaultScript; - - } - else - { - StringBuilder builder = new(); - builder.AppendLine(this.WritePageHead(targetType)); - 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(); + 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; + this.defaultScript = defaultAttr?.defaultScript ?? ""; + var descriptionAttr = targetType.GetCustomAttribute(); + this.description = descriptionAttr?.description ?? ""; + + StringBuilder builder = new(); + builder.AppendLine(this.WritePageHead(targetType)); + 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 static object GenerateRScriptVariable(string name) @@ -156,13 +181,32 @@ namespace Convention.RScript.Variable { 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 @@ -171,5 +215,10 @@ namespace Convention.RScript.Variable { return RScriptInjectVariableGenerater.GenerateRScriptVariable(name); } + + public static string Delete(object o) + { + return RScriptInjectVariableGenerater.DestoryRScriptVariable(o); + } } } diff --git a/RScriptContext.cs b/RScriptContext.cs index d6ed65a..3669965 100644 --- a/RScriptContext.cs +++ b/RScriptContext.cs @@ -309,6 +309,7 @@ namespace Convention.RScript CurrentLocalSpaceVariableNames.Clear(); CurrentLocalSpaceVariableNames.Push(new()); JumpPointerCache.Clear(); + parser.context.Imports.AddType(typeof(Variable.RScriptVariableGenerater)); foreach (var staticType in Import) { parser.context.Imports.AddType(staticType);