Add XML docs

This commit is contained in:
Stone_Red
2026-03-04 20:44:06 +01:00
parent ac78afc12f
commit a2f621d3f4
16 changed files with 347 additions and 0 deletions
@@ -2,11 +2,32 @@
namespace YesNt.Interpreter.Runtime;
/// <summary>
/// Provides per-line execution data raised through <see cref="YesNtInterpreter.OnLineExecuted"/>.
/// </summary>
public class DebugEventArgs : EventArgs
{
/// <summary>Gets the 1-based line number of the executed line within its source file.</summary>
public int LineNumber { get; internal set; }
/// <summary>
/// Gets the line content after all statement transformations have been applied
/// (e.g. after variable substitution). May differ from <see cref="OriginalLine"/>.
/// </summary>
public string CurrentLine { get; internal set; }
/// <summary>Gets the raw line content as it appeared in the source file.</summary>
public string OriginalLine { get; internal set; }
/// <summary>
/// Gets the task identifier of the task that executed this line, or <c>0</c> if the line
/// was executed on the main thread.
/// </summary>
public int TaskId { get; internal set; }
/// <summary>
/// Gets a value indicating whether this line was executed inside a background task
/// (spawned with the <c>task</c> statement).
/// </summary>
public bool IsTask { get; internal set; }
}
@@ -1,5 +1,9 @@
namespace YesNt.Interpreter.Runtime;
/// <summary>
/// Central repository of all exit/error message strings used by <see cref="RuntimeInformation.Exit"/>.
/// Keeping messages here ensures consistency and makes them easy to find or localise.
/// </summary>
internal static class ExitMessages
{
internal const string InvalidSyntax = "Invalid syntax";
@@ -2,12 +2,27 @@
namespace YesNt.Interpreter.Runtime;
/// <summary>
/// Represents one frame on the function call stack. Created when a <c>call</c> statement is
/// executed and popped when the matching <c>return</c> is reached.
/// </summary>
internal class FunctionScope(int callerLine, Stack<string> arguments)
{
/// <summary>Gets the zero-based line index to return to after this function completes.</summary>
public int CallerLine { get; } = callerLine;
/// <summary>Gets the local variable table for this function invocation.</summary>
public Dictionary<string, string> Variables { get; } = [];
/// <summary>Gets the local list table for this function invocation.</summary>
public Dictionary<string, List<string>> Lists { get; } = [];
/// <summary>Gets the local label table for this function invocation.</summary>
public Dictionary<string, int> Labels { get; } = [];
/// <summary>Gets the stack of input arguments passed to this function via <c>push_in</c>.</summary>
public Stack<string> Arguments { get; } = arguments;
/// <summary>Gets the stack of output values pushed via <c>push_out</c>, consumed by the caller via <c>%out</c>.</summary>
public Stack<string> Results { get; } = new();
}
+6
View File
@@ -1,10 +1,16 @@
namespace YesNt.Interpreter.Runtime;
/// <summary>
/// Represents a single source line together with its location metadata.
/// </summary>
internal class Line(string content, string fileName, int lineNumber)
{
/// <summary>Gets or sets the raw text content of the line.</summary>
public string Content { get; set; } = content;
/// <summary>Gets or sets the name of the source file this line originated from.</summary>
public string FileName { get; set; } = fileName;
/// <summary>Gets or sets the zero-based line index within <see cref="FileName"/>.</summary>
public int LineNumber { get; set; } = lineNumber;
}
@@ -5,6 +5,13 @@ using YesNt.Interpreter.Utilities;
namespace YesNt.Interpreter.Runtime;
/// <summary>
/// Holds all mutable runtime state for a single script execution, including variables, lists,
/// labels, functions, the call stack, the line counter, and stop flags.
/// Each background task spawned by the <c>task</c> statement owns its own
/// <see cref="RuntimeInformation"/> whose <see cref="ParentRuntimeInformation"/> points back
/// to the main execution context.
/// </summary>
internal sealed class RuntimeInformation
{
public event Action<string> OnDebugOutput;
@@ -4,12 +4,32 @@ using YesNt.Interpreter.Enums;
namespace YesNt.Interpreter.Runtime;
/// <summary>
/// A read-only snapshot of a registered statement's metadata, used for tooling such as
/// syntax highlighters. Instances are obtained from <see cref="YesNtInterpreter.StatementInformation"/>.
/// </summary>
public class StatementInformation
{
/// <summary>Gets the keyword that identifies this statement in source code.</summary>
public string Name { get; internal set; }
/// <summary>Gets where in the line the keyword is searched for.</summary>
public SearchMode SearchMode { get; internal set; }
/// <summary>Gets which sides of the keyword must be padded with a space.</summary>
public SpaceAround SpaceAround { get; internal set; }
/// <summary>Gets the syntax-highlight colour for this statement.</summary>
public ConsoleColor Color { get; internal set; }
/// <summary>
/// Gets a value indicating whether this statement is excluded from syntax highlighting.
/// </summary>
public bool IgnoreSyntaxHighlighting { get; internal set; }
/// <summary>
/// Gets the optional sub-string that must be present in the line for this statement to match,
/// or <see langword="null"/> if no separator is required.
/// </summary>
public string Separator { get; set; }
}
@@ -1,6 +1,16 @@
namespace YesNt.Interpreter.Runtime;
/// <summary>
/// Base class for all classes that host statement handler methods.
/// Subclasses declare methods decorated with <see cref="Attributes.StatementAttribute"/> or
/// <see cref="Attributes.StaticStatementAttribute"/>; the source generator
/// (<c>GeneratedStatementRegistry</c>) discovers these at compile time and wires them up.
/// </summary>
internal abstract class StatementRuntimeInformation
{
/// <summary>
/// Gets or sets the runtime state for the current execution context.
/// Injected by the generated registry before any handler is invoked.
/// </summary>
public RuntimeInformation RuntimeInfo { get; set; }
}
@@ -10,16 +10,45 @@ using YesNt.Interpreter.Utilities;
namespace YesNt.Interpreter.Runtime;
/// <summary>
/// The main entry point for executing YesNt scripts.
/// </summary>
/// <example>
/// Running a script file:
/// <code>
/// var interpreter = new YesNtInterpreter();
/// interpreter.Execute("path/to/script.ynt");
/// </code>
/// Running script lines in memory with a custom statement:
/// <code>
/// var interpreter = new YesNtInterpreter();
/// interpreter.AddStatement("log", SearchMode.StartOfLine, SpaceAround.End, args =>
/// Console.WriteLine($"[LOG] {args}"));
/// interpreter.Execute(new List&lt;string&gt; { "log hello world" });
/// </code>
/// </example>
public class YesNtInterpreter
{
/// <summary>
/// Raised after each line is executed in debug mode. The argument is <see langword="null"/>
/// when execution ends (either normally or due to an error), allowing callers to detect completion.
/// </summary>
public event Action<DebugEventArgs> OnLineExecuted;
/// <summary>
/// Raised in debug mode whenever the script produces output (e.g. via <c>print_line</c>).
/// In non-debug mode output is written directly to <see cref="Console"/>.
/// </summary>
public event Action<string> OnDebugOutput;
private readonly RuntimeInformation runtimeInfo = new RuntimeInformation();
private Dictionary<StatementAttribute, Action<string>> statements;
private readonly List<KeyValuePair<StaticStatementAttribute, Action>> staticStatements;
/// <summary>
/// Gets a read-only snapshot of all currently registered statements.
/// Useful for building syntax highlighters or documentation tools.
/// </summary>
public ReadOnlyCollection<StatementInformation> StatementInformation
{
get
@@ -41,6 +70,16 @@ public class YesNtInterpreter
}
}
/// <summary>
/// Registers a custom statement using a pre-built <see cref="StatementAttribute"/>.
/// If a statement with the same attribute key already exists it will be replaced.
/// The statement list is re-sorted by priority after insertion.
/// </summary>
/// <param name="attribute">The attribute describing the keyword, search mode, and priority.</param>
/// <param name="handler">
/// The delegate invoked when the statement matches. Receives the argument text
/// (the part of the line after the keyword, unless <see cref="StatementAttribute.KeepStatementInArgs"/> is set).
/// </param>
public void AddStatement(StatementAttribute attribute, Action<string> handler)
{
statements[attribute] = handler;
@@ -50,16 +89,34 @@ public class YesNtInterpreter
.ToDictionary(x => x.Key, x => x.Value);
}
/// <summary>
/// Registers a custom statement without a syntax-highlight colour.
/// </summary>
/// <param name="name">The keyword that identifies this statement in source code.</param>
/// <param name="searchMode">Where in the line the keyword is matched.</param>
/// <param name="spaceAround">Which sides of the keyword require a surrounding space.</param>
/// <param name="handler">The delegate invoked when the statement matches.</param>
public void AddStatement(string name, SearchMode searchMode, SpaceAround spaceAround, Action<string> handler)
{
AddStatement(new StatementAttribute(name, searchMode, spaceAround), handler);
}
/// <summary>
/// Registers a custom statement with a syntax-highlight colour.
/// </summary>
/// <param name="name">The keyword that identifies this statement in source code.</param>
/// <param name="searchMode">Where in the line the keyword is matched.</param>
/// <param name="spaceAround">Which sides of the keyword require a surrounding space.</param>
/// <param name="consoleColor">The colour used for syntax highlighting in the code editor.</param>
/// <param name="handler">The delegate invoked when the statement matches.</param>
public void AddStatement(string name, SearchMode searchMode, SpaceAround spaceAround, ConsoleColor consoleColor, Action<string> handler)
{
AddStatement(new StatementAttribute(name, searchMode, spaceAround, consoleColor), handler);
}
/// <summary>
/// Initialises a new <see cref="YesNtInterpreter"/> and registers all built-in statements.
/// </summary>
public YesNtInterpreter()
{
GeneratedStatementRegistry.Register(runtimeInfo, out statements, out staticStatements);
@@ -68,11 +125,23 @@ public class YesNtInterpreter
runtimeInfo.OnLineExecuted += e => OnLineExecuted?.Invoke(e);
}
/// <summary>
/// Requests a graceful stop of the currently executing script.
/// The interpreter will terminate at the next line boundary.
/// </summary>
public void Stop()
{
runtimeInfo.Exit(ExitMessages.TerminatedByExternalProcess, true);
}
/// <summary>
/// Executes a YesNt script file.
/// </summary>
/// <param name="path">The path to the <c>.ynt</c> script file.</param>
/// <param name="isDebugMode">
/// When <see langword="true"/>, output is routed through <see cref="OnDebugOutput"/> instead of
/// <see cref="Console"/> and line-execution events are raised via <see cref="OnLineExecuted"/>.
/// </param>
public void Execute(string path, bool isDebugMode = false)
{
runtimeInfo.Reset();
@@ -83,6 +152,14 @@ public class YesNtInterpreter
}
}
/// <summary>
/// Executes a YesNt script supplied as an in-memory list of lines.
/// </summary>
/// <param name="lines">The script lines to execute.</param>
/// <param name="isDebugMode">
/// When <see langword="true"/>, output is routed through <see cref="OnDebugOutput"/> and
/// line-execution events are raised via <see cref="OnLineExecuted"/>.
/// </param>
public void Execute(List<string> lines, bool isDebugMode = false)
{
runtimeInfo.Reset();