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