From 1760b85245ad1f7a87abc2097091c5d382de1ac8 Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:47:59 +0200 Subject: [PATCH] Generate StatementInformation classes with code generator --- .../StatementRegistryGenerator.cs | 207 +++++++++++++++++- .../AddStatementTests.cs | 8 +- .../Attributes/StatementAttributeContainer.cs | 109 --------- .../StaticStatementAttributeContainer.cs | 28 --- .../Runtime/IStatementContext.cs | 10 +- .../Runtime/StatementHandler.cs | 4 +- .../Runtime/StatementInformation.cs | 35 --- .../Runtime/YesNtInterpreter.cs | 63 ++---- 8 files changed, 229 insertions(+), 235 deletions(-) delete mode 100644 src/YesNt.Interpreter/Attributes/StatementAttributeContainer.cs delete mode 100644 src/YesNt.Interpreter/Attributes/StaticStatementAttributeContainer.cs delete mode 100644 src/YesNt.Interpreter/Runtime/StatementInformation.cs diff --git a/src/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs b/src/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs index 92d6f31..ee28b58 100644 --- a/src/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs +++ b/src/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs @@ -27,8 +27,14 @@ public sealed class StatementRegistryGenerator : IIncrementalGenerator CollectMethods(compilation.Assembly.GlobalNamespace, statementMethods, staticStatementMethods); - string source = GenerateRegistrySource(statementMethods, staticStatementMethods); - context.AddSource("GeneratedStatementRegistry.g.cs", source); + INamedTypeSymbol? statementAttrSymbol = compilation.GetTypeByMetadataName(StatementAttributeName); + INamedTypeSymbol? staticStatementAttrSymbol = compilation.GetTypeByMetadataName(StaticStatementAttributeName); + + string infoSource = GenerateInformationClassesSource(statementAttrSymbol, staticStatementAttrSymbol); + context.AddSource("GeneratedStatementInformation.g.cs", infoSource); + + string registrySource = GenerateRegistrySource(statementMethods, staticStatementMethods); + context.AddSource("GeneratedStatementRegistry.g.cs", registrySource); } private static void CollectMethods( @@ -77,6 +83,187 @@ public sealed class StatementRegistryGenerator : IIncrementalGenerator } } + // ------------------------------------------------------------------------- + // Information class generation + // ------------------------------------------------------------------------- + + private static string GenerateInformationClassesSource( + INamedTypeSymbol? statementAttrSymbol, + INamedTypeSymbol? staticStatementAttrSymbol) + { + StringBuilder sb = new StringBuilder(); + + _ = sb.AppendLine("// "); + _ = sb.AppendLine("#nullable enable"); + _ = sb.AppendLine(); + _ = sb.AppendLine("namespace YesNt.Interpreter.Runtime;"); + _ = sb.AppendLine(); + + if (statementAttrSymbol is not null) + { + EmitInformationClass(sb, statementAttrSymbol, "StatementInformation"); + } + + if (staticStatementAttrSymbol is not null) + { + EmitInformationClass(sb, staticStatementAttrSymbol, "StaticStatementInformation"); + } + + return sb.ToString(); + } + + private static void EmitInformationClass( + StringBuilder sb, + INamedTypeSymbol attributeSymbol, + string className) + { + List ctors = attributeSymbol.Constructors + .Where(c => !c.IsImplicitlyDeclared) + .OrderByDescending(c => c.Parameters.Length) + .ToList(); + + // All parameters across all ctors that are covered by a ctor (get-only properties). + HashSet ctorParamNames = new HashSet( + ctors.SelectMany(c => c.Parameters).Select(p => p.Name), + StringComparer.OrdinalIgnoreCase); + + // Settable properties NOT covered by any ctor parameter. + List settableProps = attributeSymbol + .GetMembers() + .OfType() + .Where(p => !p.IsStatic + && p.DeclaredAccessibility == Accessibility.Public + && p.SetMethod is not null + && !ctorParamNames.Contains(p.Name)) + .ToList(); + + // All properties ever assigned by any ctor, deduplicated by name. + // We need a get-only property for each of them. + List<(string PropName, ITypeSymbol PropType)> ctorProps = ctors + .SelectMany(c => c.Parameters) + .Select(p => ( + PropName: ResolvePropertyName(attributeSymbol, p), + PropType: p.Type)) + .GroupBy(x => x.PropName, StringComparer.OrdinalIgnoreCase) + .Select(g => g.First()) + .ToList(); + + // ---- class declaration ---- + _ = sb.AppendLine($"public sealed class {className}"); + _ = sb.AppendLine("{"); + + // ---- one constructor per attribute constructor ---- + foreach (IMethodSymbol ctor in ctors) + { + if (ctor.Parameters.Length == 0) + { + _ = sb.AppendLine($" public {className}() {{ }}"); + _ = sb.AppendLine(); + continue; + } + + string ctorParams = string.Join(", ", + ctor.Parameters.Select(p => $"{GlobalType(p.Type)} {p.Name}")); + + _ = sb.AppendLine($" public {className}({ctorParams})"); + _ = sb.AppendLine(" {"); + + foreach (IParameterSymbol p in ctor.Parameters) + { + string propName = ResolvePropertyName(attributeSymbol, p); + _ = sb.AppendLine($" {propName} = {p.Name};"); + } + + _ = sb.AppendLine(" }"); + _ = sb.AppendLine(); + } + + // ---- get-only properties sourced from ctor parameters ---- + foreach ((string propName, ITypeSymbol propType) in ctorProps) + { + _ = sb.AppendLine($" public {GlobalType(propType)} {propName} {{ get; }}"); + } + + // ---- settable properties (named-argument style) ---- + foreach (IPropertySymbol prop in settableProps) + { + string defaultClause = GetDefaultClause(prop); + _ = sb.AppendLine($" public {GlobalType(prop.Type)} {prop.Name} {{ get; init; }}{defaultClause}"); + } + + _ = sb.AppendLine("}"); + _ = sb.AppendLine(); + } + + // Finds the attribute property that corresponds to a constructor parameter. + private static string ResolvePropertyName(INamedTypeSymbol attributeSymbol, IParameterSymbol parameter) + { + IPropertySymbol? match = attributeSymbol + .GetMembers() + .OfType() + .FirstOrDefault(p => string.Equals(p.Name, parameter.Name, StringComparison.OrdinalIgnoreCase)); + + return match?.Name ?? ToPascalCase(parameter.Name); + } + + private static string GlobalType(ITypeSymbol type) + { + // Primitive aliases don't have a global:: form — emit the C# keyword instead. + string keyword = type.SpecialType switch + { + SpecialType.System_String => "string", + SpecialType.System_Boolean => "bool", + SpecialType.System_Byte => "byte", + SpecialType.System_SByte => "sbyte", + SpecialType.System_Int16 => "short", + SpecialType.System_UInt16 => "ushort", + SpecialType.System_Int32 => "int", + SpecialType.System_UInt32 => "uint", + SpecialType.System_Int64 => "long", + SpecialType.System_UInt64 => "ulong", + SpecialType.System_Single => "float", + SpecialType.System_Double => "double", + SpecialType.System_Decimal => "decimal", + SpecialType.System_Char => "char", + SpecialType.System_Object => "object", + _ => "" + }; + + if (keyword != "") + { + // Preserve nullability annotation (e.g. string?) + return type.NullableAnnotation == NullableAnnotation.Annotated + ? keyword + "?" + : keyword; + } + + return $"global::{type.ToDisplayString()}"; + } + + private static string ToPascalCase(string name) + { + return string.IsNullOrEmpty(name) ? name : char.ToUpperInvariant(name[0]) + name.Substring(1); + } + + private static string GetDefaultClause(IPropertySymbol prop) + { + // Only emit a default for a handful of well-known "safe" defaults so the + // generated code compiles even when the caller omits the named argument. + return prop.Type.IsReferenceType || prop.Type.NullableAnnotation == NullableAnnotation.Annotated + ? " = null!;" + : prop.Type.SpecialType switch + { + SpecialType.System_Boolean => " = false;", + SpecialType.System_Int32 => " = 0;", + SpecialType.System_String => " = \"\";", + _ => "" + }; + } + + // ------------------------------------------------------------------------- + // Registry source generation (unchanged from original) + // ------------------------------------------------------------------------- + private static string GenerateRegistrySource( List statementMethods, List staticStatementMethods) @@ -94,8 +281,8 @@ public sealed class StatementRegistryGenerator : IIncrementalGenerator _ = sb.AppendLine("{"); _ = sb.AppendLine(" internal static void Register("); _ = sb.AppendLine(" RuntimeInformation runtimeInfo,"); - _ = sb.AppendLine(" out Dictionary> statements,"); - _ = sb.AppendLine(" out List> staticStatements)"); + _ = sb.AppendLine(" out Dictionary> statements,"); + _ = sb.AppendLine(" out List> staticStatements)"); _ = sb.AppendLine(" {"); List allTypes = statementMethods @@ -116,25 +303,25 @@ public sealed class StatementRegistryGenerator : IIncrementalGenerator _ = sb.AppendLine($" {instanceName}.RuntimeInfo = runtimeInfo;"); } - _ = sb.AppendLine(" var statementEntries = new List>>();"); + _ = sb.AppendLine(" var statementEntries = new List>>();"); foreach (MethodRegistration method in statementMethods .OrderBy(x => x.ContainingType.ToDisplayString()) .ThenBy(x => x.Method.Name)) { string instanceName = instanceNames[method.ContainingType]; - string attributeCreation = BuildAttributeCreation("global::YesNt.Interpreter.Attributes.StatementAttributeContainer", method.Attribute); + string attributeCreation = BuildAttributeCreation("global::YesNt.Interpreter.Runtime.StatementInformation", method.Attribute); _ = sb.AppendLine($" statementEntries.Add(new({attributeCreation}, {instanceName}.{method.Method.Name}));"); } - _ = sb.AppendLine(" var staticEntries = new List>();"); + _ = sb.AppendLine(" var staticEntries = new List>();"); foreach (MethodRegistration method in staticStatementMethods .OrderBy(x => x.ContainingType.ToDisplayString()) .ThenBy(x => x.Method.Name)) { string instanceName = instanceNames[method.ContainingType]; - string attributeCreation = BuildAttributeCreation("global::YesNt.Interpreter.Attributes.StaticStatementAttributeContainer", method.Attribute); + string attributeCreation = BuildAttributeCreation("global::YesNt.Interpreter.Runtime.StaticStatementInformation", method.Attribute); _ = sb.AppendLine($" staticEntries.Add(new({attributeCreation}, {instanceName}.{method.Method.Name}));"); } @@ -143,7 +330,7 @@ public sealed class StatementRegistryGenerator : IIncrementalGenerator _ = sb.AppendLine(" int cmp = a.Key.Priority.CompareTo(b.Key.Priority);"); _ = sb.AppendLine(" return cmp != 0 ? cmp : b.Key.Name.Length.CompareTo(a.Key.Name.Length);"); _ = sb.AppendLine(" });"); - _ = sb.AppendLine(" statements = new Dictionary>();"); + _ = sb.AppendLine(" statements = new Dictionary>();"); _ = sb.AppendLine(" foreach (var entry in statementEntries)"); _ = sb.AppendLine(" statements.Add(entry.Key, entry.Value);"); _ = sb.AppendLine(); @@ -236,4 +423,4 @@ public sealed class StatementRegistryGenerator : IIncrementalGenerator public AttributeData Attribute { get; } = attribute; } -} +} \ No newline at end of file diff --git a/src/YesNt.Interpreter.Tests/AddStatementTests.cs b/src/YesNt.Interpreter.Tests/AddStatementTests.cs index 73d8c14..1aeb9d2 100644 --- a/src/YesNt.Interpreter.Tests/AddStatementTests.cs +++ b/src/YesNt.Interpreter.Tests/AddStatementTests.cs @@ -2,8 +2,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Collections.Generic; -using YesNt.Interpreter.Attributes; using YesNt.Interpreter.Enums; +using YesNt.Interpreter.Runtime; namespace YesNt.Interpreter.Tests; @@ -64,7 +64,7 @@ public class AddStatementTests _ = YesNtAssert.GetLastLineWithSetup(lines, interpreter => { - StatementAttributeContainer attr = new StatementAttributeContainer("attr_cmd", SearchMode.StartOfLine, SpaceAround.End); + StatementInformation attr = new StatementInformation("attr_cmd", SearchMode.StartOfLine, SpaceAround.End); interpreter.AddStatement(attr, _ => { handlerCalled = true; @@ -281,11 +281,11 @@ public class AddStatementTests _ = YesNtAssert.GetLastLineWithSetup(lines, interpreter => { interpreter.AddStatement( - new StatementAttributeContainer("priority_cmd", SearchMode.StartOfLine, SpaceAround.End) { Priority = Priority.High }, + new StatementInformation("priority_cmd", SearchMode.StartOfLine, SpaceAround.End) { Priority = Priority.High }, _ => highPriorityOrder = callOrder++); interpreter.AddStatement( - new StatementAttributeContainer("priority_cmd", SearchMode.StartOfLine, SpaceAround.End) { Priority = Priority.Normal }, + new StatementInformation("priority_cmd", SearchMode.StartOfLine, SpaceAround.End) { Priority = Priority.Normal }, _ => normalPriorityOrder = callOrder++); }); diff --git a/src/YesNt.Interpreter/Attributes/StatementAttributeContainer.cs b/src/YesNt.Interpreter/Attributes/StatementAttributeContainer.cs deleted file mode 100644 index 275bfb5..0000000 --- a/src/YesNt.Interpreter/Attributes/StatementAttributeContainer.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; - -using YesNt.Interpreter.Enums; - -namespace YesNt.Interpreter.Attributes; - -/// -/// Marks a method as a YesNt statement handler. -/// The interpreter matches source lines against the keyword according to -/// and rules, then invokes the decorated method -/// with the remaining argument text. -/// -/// -/// Methods decorated with this attribute must be instance methods on a class that inherits -/// and must accept a single parameter. -/// -public class StatementAttributeContainer -{ - /// Gets the keyword that identifies this statement in source code. - public string Name { get; } - - /// Gets where in the line the keyword is searched for. - public SearchMode SearchMode { get; } - - /// Gets which sides of the keyword must be padded with a space. - public SpaceAround SpaceAround { get; } - - /// Gets or sets the syntax-highlight color used by the code editor. - public ConsoleColor Color { get; set; } - - /// - /// Gets or sets the execution priority. Statements with a lower value - /// run before those with a higher value. Defaults to . - /// - public Priority Priority { get; set; } = Priority.Normal; - - /// - /// Gets or sets a value indicating whether this statement is still invoked while the interpreter - /// is in search mode (scanning for a label or function definition). Defaults to . - /// - public bool ExecuteInSearchMode { get; set; } - - /// - /// Gets or sets a value indicating whether the full current line (including the keyword itself) - /// is passed as the argument, rather than stripping the keyword prefix/suffix first. - /// Defaults to . - /// - public bool KeepStatementInArgs { get; set; } - - /// - /// Gets a value indicating whether this statement should be excluded from syntax highlighting. - /// Set to when no is provided. - /// - public bool IgnoreSyntaxHighlighting { get; } - - /// - /// Gets or sets an optional sub-string that must also be present in the line for this statement - /// to match. Used to differentiate overloaded keywords (e.g. call vs call … with …). - /// - public string Separator { get; set; } - - /// - /// Gets or sets the name of the statement that marks the end of this block. - /// Used for block boundary caching (e.g., "while" has BlockPair = "end_while"). - /// - public string BlockPair { get; set; } - - /// - /// Gets or sets a value indicating whether this statement is the end of a block. - /// Used for block boundary caching (e.g., "end_while" has IsBlockEnd = true). - /// - public bool IsBlockEnd { get; set; } - - /// - /// Gets or sets a value indicating whether this statement is an intermediate part of a block - /// (e.g., "else:" between "if" and "end_if"). - /// - public bool IsBlockIntermediate { get; set; } - - /// - /// Initializes a new with a syntax-highlight color. - /// - /// The keyword that identifies this statement. - /// Where in the line the keyword is matched. - /// Which sides of the keyword require a surrounding space. - /// The color used for syntax highlighting in the code editor. - public StatementAttributeContainer(string name, SearchMode searchMode, SpaceAround spaceAround, ConsoleColor color) - { - Name = name; - SearchMode = searchMode; - SpaceAround = spaceAround; - Color = color; - } - - /// - /// Initializes a new without a syntax-highlight color. - /// The statement will be excluded from syntax highlighting. - /// - /// The keyword that identifies this statement. - /// Where in the line the keyword is matched. - /// Which sides of the keyword require a surrounding space. - public StatementAttributeContainer(string name, SearchMode searchMode, SpaceAround spaceAround) - { - Name = name; - SearchMode = searchMode; - SpaceAround = spaceAround; - IgnoreSyntaxHighlighting = true; - } -} \ No newline at end of file diff --git a/src/YesNt.Interpreter/Attributes/StaticStatementAttributeContainer.cs b/src/YesNt.Interpreter/Attributes/StaticStatementAttributeContainer.cs deleted file mode 100644 index 3d8afa4..0000000 --- a/src/YesNt.Interpreter/Attributes/StaticStatementAttributeContainer.cs +++ /dev/null @@ -1,28 +0,0 @@ -using YesNt.Interpreter.Enums; - -namespace YesNt.Interpreter.Attributes; - -/// -/// Marks a parameterless method as a YesNt static statement handler. -/// Static statements are invoked once per line before regular statement matching begins, -/// regardless of whether the line matches any keyword. They are typically used for -/// pre-processing tasks such as transforming the current line before other statements run. -/// -/// -/// Methods decorated with this attribute must be instance methods on a class that inherits -/// and must have no parameters. -/// -public class StaticStatementAttributeContainer -{ - /// - /// Gets or sets a value indicating whether this handler is still invoked while the interpreter - /// is in search mode (scanning for a label or function definition). Defaults to . - /// - public bool ExecuteInSearchMode { get; set; } - - /// - /// Gets or sets the execution priority relative to other static statements. - /// Defaults to . - /// - public Priority Priority { get; set; } = Priority.Normal; -} \ No newline at end of file diff --git a/src/YesNt.Interpreter/Runtime/IStatementContext.cs b/src/YesNt.Interpreter/Runtime/IStatementContext.cs index 58569e8..7fc9f8d 100644 --- a/src/YesNt.Interpreter/Runtime/IStatementContext.cs +++ b/src/YesNt.Interpreter/Runtime/IStatementContext.cs @@ -4,7 +4,7 @@ namespace YesNt.Interpreter.Runtime; /// /// Exposes the script runtime state accessible to custom statement handlers registered -/// via . +/// via . /// public interface IStatementContext { @@ -24,9 +24,9 @@ public interface IStatementContext /// Terminates execution with the given message. /// The message written to debug output. - /// - /// to signal an error termination; - /// for a planned, non-error termination. + /// + /// If , also terminates all tasks spawned by the task statement. + /// If , only terminates the current execution context (main script or individual task). /// - void Exit(string message, bool isError); + void Exit(string message, bool stopAllTasks); } diff --git a/src/YesNt.Interpreter/Runtime/StatementHandler.cs b/src/YesNt.Interpreter/Runtime/StatementHandler.cs index b45d590..e98b37c 100644 --- a/src/YesNt.Interpreter/Runtime/StatementHandler.cs +++ b/src/YesNt.Interpreter/Runtime/StatementHandler.cs @@ -1,10 +1,8 @@ using System; -using YesNt.Interpreter.Attributes; - namespace YesNt.Interpreter.Runtime; /// /// Pre-calculated statement handler information for faster matching. /// -internal record StatementHandler(StatementAttributeContainer Attribute, Action Handler, string FullName); \ No newline at end of file +internal record StatementHandler(StatementInformation Attribute, Action Handler, string FullName); \ No newline at end of file diff --git a/src/YesNt.Interpreter/Runtime/StatementInformation.cs b/src/YesNt.Interpreter/Runtime/StatementInformation.cs deleted file mode 100644 index 5e522b1..0000000 --- a/src/YesNt.Interpreter/Runtime/StatementInformation.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; - -using YesNt.Interpreter.Enums; - -namespace YesNt.Interpreter.Runtime; - -/// -/// A read-only snapshot of a registered statement's metadata, used for tooling such as -/// syntax highlighters. Instances are obtained from . -/// -public class StatementInformation -{ - /// Gets the keyword that identifies this statement in source code. - public string Name { get; internal set; } - - /// Gets where in the line the keyword is searched for. - public SearchMode SearchMode { get; internal set; } - - /// Gets which sides of the keyword must be padded with a space. - public SpaceAround SpaceAround { get; internal set; } - - /// Gets the syntax-highlight color for this statement. - public ConsoleColor Color { get; internal set; } - - /// - /// Gets a value indicating whether this statement is excluded from syntax highlighting. - /// - public bool IgnoreSyntaxHighlighting { get; internal set; } - - /// - /// Gets the optional sub-string that must be present in the line for this statement to match, - /// or if no separator is required. - /// - public string Separator { get; set; } -} \ No newline at end of file diff --git a/src/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/src/YesNt.Interpreter/Runtime/YesNtInterpreter.cs index c7be90b..813c34d 100644 --- a/src/YesNt.Interpreter/Runtime/YesNtInterpreter.cs +++ b/src/YesNt.Interpreter/Runtime/YesNtInterpreter.cs @@ -29,36 +29,17 @@ public class YesNtInterpreter public event Action OnDebugOutput; private readonly RuntimeInformation runtimeInfo = new RuntimeInformation(); - private Dictionary> statements; + private Dictionary> statements; private List statementHandlers; private List> lineMatchingHandlers = []; - private readonly List> staticStatements; - private readonly Dictionary>>> disabledStatements = []; + private readonly List> staticStatements; + private readonly Dictionary>>> disabledStatements = []; /// /// Gets a read-only snapshot of all currently registered statements. /// Useful for building syntax highlighters or documentation tools. /// - public ReadOnlyCollection StatementInformation - { - get - { - List information = statements.Select(s => - { - return new StatementInformation() - { - Name = s.Key.Name, - SearchMode = s.Key.SearchMode, - SpaceAround = s.Key.SpaceAround, - Color = s.Key.Color, - IgnoreSyntaxHighlighting = s.Key.IgnoreSyntaxHighlighting, - Separator = s.Key.Separator - }; - }).ToList(); - - return new ReadOnlyCollection(information); - } - } + public ReadOnlyCollection StatementInformation => statements.Keys.ToList().AsReadOnly(); /// /// from the moment (or any @@ -96,7 +77,7 @@ public class YesNtInterpreter } /// - /// Registers a custom statement using a pre-built . + /// Registers a custom statement using a pre-built . /// If a statement with the same attribute key (identical field values) already exists it will be replaced; /// otherwise a new entry is added. Built-in statements use distinct attribute instances, so passing a /// newly constructed attribute with the same name will add a second handler rather than replacing @@ -106,13 +87,13 @@ public class YesNtInterpreter /// The attribute describing the keyword, search mode, and priority. /// /// The delegate invoked when the statement matches. Receives the argument text - /// (the part of the line after the keyword, unless is set). + /// (the part of the line after the keyword, unless is set). /// - public void AddStatement(StatementAttributeContainer attribute, Action handler) + public void AddStatement(StatementInformation attribute, Action handler) { statements[attribute] = handler; - List>> entries = [.. statements]; + List>> entries = [.. statements]; entries.Sort((a, b) => { int cmp = a.Key.Priority.CompareTo(b.Key.Priority); @@ -121,7 +102,7 @@ public class YesNtInterpreter statements = []; - foreach (KeyValuePair> entry in entries) + foreach (KeyValuePair> entry in entries) { statements.Add(entry.Key, entry.Value); } @@ -139,7 +120,7 @@ public class YesNtInterpreter /// The delegate invoked when the statement matches. Receives the argument text and the current /// for reading/writing script state. /// - public void AddStatement(StatementAttributeContainer attribute, Action handler) + public void AddStatement(StatementInformation attribute, Action handler) { AddStatement(attribute, args => handler(args, runtimeInfo)); } @@ -153,7 +134,7 @@ public class YesNtInterpreter /// The delegate invoked when the statement matches. public void AddStatement(string name, SearchMode searchMode, SpaceAround spaceAround, Action handler) { - AddStatement(new StatementAttributeContainer(name, searchMode, spaceAround), handler); + AddStatement(new StatementInformation(name, searchMode, spaceAround), handler); } /// @@ -169,7 +150,7 @@ public class YesNtInterpreter /// public void AddStatement(string name, SearchMode searchMode, SpaceAround spaceAround, Action handler) { - AddStatement(new StatementAttributeContainer(name, searchMode, spaceAround), handler); + AddStatement(new StatementInformation(name, searchMode, spaceAround), handler); } /// @@ -182,7 +163,7 @@ public class YesNtInterpreter /// The delegate invoked when the statement matches. public void AddStatement(string name, SearchMode searchMode, SpaceAround spaceAround, ConsoleColor consoleColor, Action handler) { - AddStatement(new StatementAttributeContainer(name, searchMode, spaceAround, consoleColor), handler); + AddStatement(new StatementInformation(name, searchMode, spaceAround, consoleColor), handler); } /// @@ -199,7 +180,7 @@ public class YesNtInterpreter /// public void AddStatement(string name, SearchMode searchMode, SpaceAround spaceAround, ConsoleColor consoleColor, Action handler) { - AddStatement(new StatementAttributeContainer(name, searchMode, spaceAround, consoleColor), handler); + AddStatement(new StatementInformation(name, searchMode, spaceAround, consoleColor), handler); } /// @@ -208,7 +189,7 @@ public class YesNtInterpreter /// The keyword to remove. public void RemoveStatement(string name) { - foreach (StatementAttributeContainer key in statements.Keys.Where(k => k.Name == name).ToList()) + foreach (StatementInformation key in statements.Keys.Where(k => k.Name == name).ToList()) { _ = statements.Remove(key); } @@ -231,7 +212,7 @@ public class YesNtInterpreter return; } - List>> matching = + List>> matching = statements.Where(kv => kv.Key.Name == name).ToList(); if (matching.Count == 0) @@ -241,7 +222,7 @@ public class YesNtInterpreter disabledStatements[name] = matching; - foreach (KeyValuePair> kv in matching) + foreach (KeyValuePair> kv in matching) { statements[kv.Key] = _ => { }; } @@ -257,12 +238,12 @@ public class YesNtInterpreter /// The keyword of the statement(s) to re-enable. public void EnableStatement(string name) { - if (!disabledStatements.TryGetValue(name, out List>> saved)) + if (!disabledStatements.TryGetValue(name, out List>> saved)) { return; } - foreach (KeyValuePair> kv in saved) + foreach (KeyValuePair> kv in saved) { statements[kv.Key] = kv.Value; } @@ -479,7 +460,7 @@ public class YesNtInterpreter }; } - foreach (KeyValuePair staticStatement in staticStatements) + foreach (KeyValuePair staticStatement in staticStatements) { if (!staticStatement.Key.ExecuteInSearchMode && runtimeInfo.IsSearching) { @@ -498,7 +479,7 @@ public class YesNtInterpreter foreach (StatementHandler handler in handlers) { - StatementAttributeContainer statementAttribute = handler.Attribute; + StatementInformation statementAttribute = handler.Attribute; if (!statementAttribute.ExecuteInSearchMode && runtimeInfo.IsSearching) { @@ -681,7 +662,7 @@ public class YesNtInterpreter private static bool IsPossibleMatch(string content, StatementHandler handler) { - StatementAttributeContainer attr = handler.Attribute; + StatementInformation attr = handler.Attribute; string fullName = handler.FullName; return attr.SearchMode switch