mirror of
https://github.com/Stone-Red-Code/YesNt-Interpreter.git
synced 2026-09-09 16:06:08 +02:00
- Add tasks
- Add check if file exist - Improved code structure
This commit is contained in:
@@ -1,12 +1,21 @@
|
|||||||
namespace YesNt.Interpreter
|
using System;
|
||||||
|
|
||||||
|
namespace YesNt.Interpreter
|
||||||
{
|
{
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
private static void Main(string[] args)
|
private static void Main(string[] args)
|
||||||
{
|
{
|
||||||
YesNtInterpreter interpreter = new YesNtInterpreter();
|
if (args.Length == 1)
|
||||||
interpreter.Initialize();
|
{
|
||||||
interpreter.Execute(args[0]);
|
YesNtInterpreter interpreter = new YesNtInterpreter();
|
||||||
|
interpreter.Initialize();
|
||||||
|
interpreter.Execute(args[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("No path specified!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using YesNt.Interpreter.Runtime;
|
||||||
using YesNt.Interpreter.Utilities;
|
using YesNt.Interpreter.Utilities;
|
||||||
|
|
||||||
namespace YesNt.Interpreter
|
namespace YesNt.Interpreter
|
||||||
{
|
{
|
||||||
internal class RuntimeInformation
|
internal class RuntimeInformation
|
||||||
{
|
{
|
||||||
|
private RuntimeInformation parentRuntimeInformation;
|
||||||
|
|
||||||
public Dictionary<string, string> Variables { get; } = new();
|
public Dictionary<string, string> Variables { get; } = new();
|
||||||
public Dictionary<string, int> Labels { get; } = new();
|
public Dictionary<string, int> Labels { get; } = new();
|
||||||
public List<string> Lines { get; set; } = new();
|
public List<string> Lines { get; set; } = new();
|
||||||
@@ -15,15 +18,52 @@ namespace YesNt.Interpreter
|
|||||||
public string SearchLabel { get; set; } = string.Empty;
|
public string SearchLabel { get; set; } = string.Empty;
|
||||||
public int LineNumber { get; set; } = 0;
|
public int LineNumber { get; set; } = 0;
|
||||||
public bool Stop { get; private set; } = false;
|
public bool Stop { get; private set; } = false;
|
||||||
public bool IsDebugMode { get; set; }
|
public bool StopAllTasks { get; private set; } = false;
|
||||||
|
public bool IsDebugMode { get; set; } = false;
|
||||||
|
public string CurrentFilePath { get; set; } = string.Empty;
|
||||||
|
public bool IsTask => ParentRuntimeInformation is not null;
|
||||||
|
|
||||||
|
public RuntimeInformation ParentRuntimeInformation
|
||||||
|
{
|
||||||
|
get => parentRuntimeInformation;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
parentRuntimeInformation = value;
|
||||||
|
if (parentRuntimeInformation is not null)
|
||||||
|
{
|
||||||
|
parentRuntimeInformation.OnExit += ParentRuntimeInformation_OnExit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private event Action<string, bool> OnExit;
|
||||||
|
|
||||||
public event Action<string> OnDebugOutput;
|
public event Action<string> OnDebugOutput;
|
||||||
|
|
||||||
|
public event Action<DebugEventArgs> OnLineExecuted;
|
||||||
|
|
||||||
|
private void ParentRuntimeInformation_OnExit(string exitMessage, bool stopChildTasks)
|
||||||
|
{
|
||||||
|
Exit($"Parent task was terminated!", stopChildTasks);
|
||||||
|
}
|
||||||
|
|
||||||
public void WriteLine(string output)
|
public void WriteLine(string output)
|
||||||
{
|
{
|
||||||
|
if (Stop)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsDebugMode)
|
if (IsDebugMode)
|
||||||
{
|
{
|
||||||
OnDebugOutput?.Invoke(output.FromSaveString() + Environment.NewLine);
|
if (IsTask)
|
||||||
|
{
|
||||||
|
parentRuntimeInformation.WriteLine(output.FromSaveString() + Environment.NewLine);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OnDebugOutput?.Invoke(output.FromSaveString() + Environment.NewLine);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -33,9 +73,21 @@ namespace YesNt.Interpreter
|
|||||||
|
|
||||||
public void Write(string output)
|
public void Write(string output)
|
||||||
{
|
{
|
||||||
|
if (Stop)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsDebugMode)
|
if (IsDebugMode)
|
||||||
{
|
{
|
||||||
OnDebugOutput?.Invoke(output.FromSaveString());
|
if (IsTask)
|
||||||
|
{
|
||||||
|
parentRuntimeInformation.Write(output.FromSaveString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OnDebugOutput?.Invoke(output.FromSaveString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -43,21 +95,45 @@ namespace YesNt.Interpreter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Exit(string message)
|
public void Exit(string message, bool stopAllTasks)
|
||||||
{
|
{
|
||||||
WriteLine($"{Environment.NewLine}[The process was terminated at line {LineNumber + 1} with the message: {message}]");
|
if (!Stop)
|
||||||
Stop = true;
|
{
|
||||||
|
WriteLine($"{Environment.NewLine}[{(IsTask ? "A child task" : "The process")} was terminated at line {LineNumber + 1} with the message: {message}]");
|
||||||
|
Stop = true;
|
||||||
|
}
|
||||||
|
if (stopAllTasks == true && StopAllTasks == false)
|
||||||
|
{
|
||||||
|
StopAllTasks = true;
|
||||||
|
OnExit?.Invoke(message, StopAllTasks);
|
||||||
|
parentRuntimeInformation?.Exit("Terminated by child task", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LineExecuted(DebugEventArgs debugEventArgs)
|
||||||
|
{
|
||||||
|
if (IsTask)
|
||||||
|
{
|
||||||
|
parentRuntimeInformation.LineExecuted(debugEventArgs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OnLineExecuted?.Invoke(debugEventArgs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
CurrentLine = string.Empty;
|
|
||||||
Lines.Clear();
|
Lines.Clear();
|
||||||
Variables.Clear();
|
Variables.Clear();
|
||||||
Labels.Clear();
|
Labels.Clear();
|
||||||
LabelStack.Clear();
|
LabelStack.Clear();
|
||||||
|
ParentRuntimeInformation = null;
|
||||||
SearchLabel = string.Empty;
|
SearchLabel = string.Empty;
|
||||||
|
CurrentFilePath = string.Empty;
|
||||||
|
CurrentLine = string.Empty;
|
||||||
Stop = false;
|
Stop = false;
|
||||||
|
StopAllTasks = false;
|
||||||
IsDebugMode = false;
|
IsDebugMode = false;
|
||||||
LineNumber = 0;
|
LineNumber = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ namespace YesNt.Interpreter
|
|||||||
|
|
||||||
public event Action<string> OnDebugOutput;
|
public event Action<string> OnDebugOutput;
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
runtimeInfo.Exit("Terminated by external process", true);
|
||||||
|
}
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||||
@@ -80,6 +85,7 @@ namespace YesNt.Interpreter
|
|||||||
staticStatements = staticStatements.OrderBy(s => s.Key.Priority).ToList();
|
staticStatements = staticStatements.OrderBy(s => s.Key.Priority).ToList();
|
||||||
|
|
||||||
runtimeInfo.OnDebugOutput += (s) => OnDebugOutput?.Invoke(s);
|
runtimeInfo.OnDebugOutput += (s) => OnDebugOutput?.Invoke(s);
|
||||||
|
runtimeInfo.OnLineExecuted += (DebugEventArgs e) => OnLineExecuted.Invoke(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Execute(string path, bool isDebugMode = false)
|
public void Execute(string path, bool isDebugMode = false)
|
||||||
@@ -87,8 +93,27 @@ namespace YesNt.Interpreter
|
|||||||
runtimeInfo.Reset();
|
runtimeInfo.Reset();
|
||||||
runtimeInfo.IsDebugMode = isDebugMode;
|
runtimeInfo.IsDebugMode = isDebugMode;
|
||||||
LoadFile(path);
|
LoadFile(path);
|
||||||
|
Execute();
|
||||||
|
}
|
||||||
|
|
||||||
for (runtimeInfo.LineNumber = 0; runtimeInfo.LineNumber < runtimeInfo.Lines.Count; runtimeInfo.LineNumber++)
|
internal void Execute(List<string> lines, int startLine, RuntimeInformation parentRuntimeInformation)
|
||||||
|
{
|
||||||
|
runtimeInfo.Reset();
|
||||||
|
runtimeInfo.IsDebugMode = parentRuntimeInformation.IsDebugMode;
|
||||||
|
runtimeInfo.Lines = lines;
|
||||||
|
runtimeInfo.LineNumber = startLine;
|
||||||
|
runtimeInfo.ParentRuntimeInformation = parentRuntimeInformation;
|
||||||
|
if (parentRuntimeInformation.StopAllTasks)
|
||||||
|
{
|
||||||
|
runtimeInfo.Exit($"Parent task was terminated!", parentRuntimeInformation.StopAllTasks);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Execute()
|
||||||
|
{
|
||||||
|
for (; runtimeInfo.LineNumber < runtimeInfo.Lines.Count; runtimeInfo.LineNumber++)
|
||||||
{
|
{
|
||||||
if (runtimeInfo.Stop)
|
if (runtimeInfo.Stop)
|
||||||
{
|
{
|
||||||
@@ -173,18 +198,25 @@ namespace YesNt.Interpreter
|
|||||||
|
|
||||||
if (!statementFound)
|
if (!statementFound)
|
||||||
{
|
{
|
||||||
runtimeInfo.Exit("Invalid statement");
|
runtimeInfo.Exit("Invalid statement", true);
|
||||||
}
|
}
|
||||||
if (isDebugMode && searchingLabel)
|
if (runtimeInfo.IsDebugMode && searchingLabel)
|
||||||
{
|
{
|
||||||
debugEventArgs.CurrentLine = runtimeInfo.CurrentLine.FromSaveString();
|
debugEventArgs.CurrentLine = runtimeInfo.CurrentLine.FromSaveString();
|
||||||
OnLineExecuted?.Invoke(debugEventArgs);
|
runtimeInfo.LineExecuted(debugEventArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runtimeInfo.Stop == false)
|
if (runtimeInfo.Stop == false)
|
||||||
{
|
{
|
||||||
runtimeInfo.Exit("End of file");
|
if (string.IsNullOrWhiteSpace(runtimeInfo.SearchLabel))
|
||||||
|
{
|
||||||
|
runtimeInfo.Exit("End of file", false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
runtimeInfo.Exit($"Label \"{runtimeInfo.SearchLabel}\" not found", false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +224,7 @@ namespace YesNt.Interpreter
|
|||||||
{
|
{
|
||||||
if (!File.Exists(path))
|
if (!File.Exists(path))
|
||||||
{
|
{
|
||||||
runtimeInfo.WriteLine($"File \"{path}\" not found!");
|
runtimeInfo.Exit($"File \"{path}\" not found!", true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,199 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
using YesNt.Interpreter.Attributes;
|
|
||||||
using YesNt.Interpreter.Enums;
|
|
||||||
using YesNt.Interpreter.Utilities;
|
|
||||||
|
|
||||||
namespace YesNt.Interpreter
|
|
||||||
{
|
|
||||||
internal class Statements : StatementRuntimeInformation
|
|
||||||
{
|
|
||||||
[Statement("cwl", SearchMode.StartOfLine, SpaceAround.End, Priority = Priority.VeryLow)]
|
|
||||||
public void WriteLine(string args)
|
|
||||||
{
|
|
||||||
RuntimeInfo.WriteLine(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Statement("cw", SearchMode.StartOfLine, SpaceAround.End, Priority = Priority.VeryLow)]
|
|
||||||
public void Write(string args)
|
|
||||||
{
|
|
||||||
RuntimeInfo.Write(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Statement("%crl", SearchMode.Contains, SpaceAround.End, KeepStatementInArgs = true, Priority = Priority.Highest)]
|
|
||||||
public void ReadLine(string args)
|
|
||||||
{
|
|
||||||
args += " ";
|
|
||||||
while (args.Contains("%crl "))
|
|
||||||
{
|
|
||||||
args = args.ReplaceFirstOccurrence("%crl ", Console.ReadLine().ToSaveString() + " ");
|
|
||||||
}
|
|
||||||
RuntimeInfo.CurrentLine = args.TrimEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Statement("%cr", SearchMode.Contains, SpaceAround.End, KeepStatementInArgs = true, Priority = Priority.Highest)]
|
|
||||||
public void ReadKey(string args)
|
|
||||||
{
|
|
||||||
args += " ";
|
|
||||||
while (args.Contains("%cr "))
|
|
||||||
{
|
|
||||||
args = args.ReplaceFirstOccurrence("%cr ", Console.ReadKey().KeyChar.ToString().ToSaveString() + " ");
|
|
||||||
}
|
|
||||||
RuntimeInfo.CurrentLine = args.TrimEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Statement("jmp", SearchMode.StartOfLine, SpaceAround.End)]
|
|
||||||
public void Jump(string args)
|
|
||||||
{
|
|
||||||
string key = args.Trim();
|
|
||||||
RuntimeInfo.LabelStack.Push(RuntimeInfo.LineNumber);
|
|
||||||
|
|
||||||
if (RuntimeInfo.Labels.ContainsKey(key))
|
|
||||||
{
|
|
||||||
RuntimeInfo.LineNumber = RuntimeInfo.Labels[key];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RuntimeInfo.SearchLabel = key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Statement("jif", SearchMode.StartOfLine, SpaceAround.End)]
|
|
||||||
public void JumpIf(string args)
|
|
||||||
{
|
|
||||||
string[] parts = args.Split('|');
|
|
||||||
if (parts.Length != 2)
|
|
||||||
{
|
|
||||||
RuntimeInfo.Exit("Invalid syntax");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string key = parts[0].Trim();
|
|
||||||
string condition = parts[1].Trim();
|
|
||||||
|
|
||||||
bool? result = Evaluator.EvaluateCondition(condition);
|
|
||||||
|
|
||||||
if (result != true)
|
|
||||||
{
|
|
||||||
if (result is null)
|
|
||||||
{
|
|
||||||
RuntimeInfo.Exit("Invalid operation");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RuntimeInfo.LabelStack.Push(RuntimeInfo.LineNumber);
|
|
||||||
|
|
||||||
if (RuntimeInfo.Labels.ContainsKey(key))
|
|
||||||
{
|
|
||||||
RuntimeInfo.LineNumber = RuntimeInfo.Labels[key];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RuntimeInfo.SearchLabel = key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Statement("lbl", SearchMode.StartOfLine, SpaceAround.End, ExecuteInSearchLabelMode = true)]
|
|
||||||
public void FindLabel(string args)
|
|
||||||
{
|
|
||||||
string key = args.Trim();
|
|
||||||
if (RuntimeInfo.Labels.ContainsKey(key))
|
|
||||||
{
|
|
||||||
RuntimeInfo.Labels[key] = RuntimeInfo.LineNumber;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RuntimeInfo.Labels.Add(key, RuntimeInfo.LineNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(RuntimeInfo.SearchLabel) && RuntimeInfo.SearchLabel == key)
|
|
||||||
{
|
|
||||||
RuntimeInfo.SearchLabel = string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Statement("ret", SearchMode.Exact, SpaceAround.None)]
|
|
||||||
public void Return(string _)
|
|
||||||
{
|
|
||||||
if (RuntimeInfo.LabelStack.Count > 0)
|
|
||||||
{
|
|
||||||
RuntimeInfo.LineNumber = RuntimeInfo.LabelStack.Pop();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RuntimeInfo.Exit("No label in stack");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Statement("end", SearchMode.Exact, SpaceAround.None)]
|
|
||||||
public void End(string _)
|
|
||||||
{
|
|
||||||
RuntimeInfo.Exit("Planned termination by code");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Statement("!calc", SearchMode.EndOfLine, SpaceAround.Start, Priority = Priority.High, ExecuteInSearchLabelMode = true)]
|
|
||||||
public void Calculate(string args)
|
|
||||||
{
|
|
||||||
MatchCollection matches = Regex.Matches(args, @"((\)?)+(\(?)+[0-9]+(((\s?)+(\)?)(\s?)+\+(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\-(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\*(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\/(\s?)+(\(?)+(\s?)+)|[,.])(?=[0-9])+)+[0-9]+(\)?)+");
|
|
||||||
|
|
||||||
for (int i = 0; i < matches.Count; i++)
|
|
||||||
{
|
|
||||||
string res = Evaluator.Calculate(matches[i].Value);
|
|
||||||
if (res is null)
|
|
||||||
{
|
|
||||||
RuntimeInfo.Exit("Invalid operation");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
args = args.Replace(matches[0].Value, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
RuntimeInfo.CurrentLine = args;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Statement("!eval", SearchMode.EndOfLine, SpaceAround.Start, Priority = Priority.VeryHigh, ExecuteInSearchLabelMode = true)]
|
|
||||||
public void Evaluate(string args)
|
|
||||||
{
|
|
||||||
RuntimeInfo.CurrentLine = args.FromSaveString();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Statement("<", SearchMode.StartOfLine, SpaceAround.None, Priority = Priority.VeryLow, IgnoreSyntaxHighlighting = true)]
|
|
||||||
public void DefineVariable(string args)
|
|
||||||
{
|
|
||||||
string[] parts = args.Split('=');
|
|
||||||
if (parts.Length == 2)
|
|
||||||
{
|
|
||||||
string key = parts[0].Replace("<", "").Trim();
|
|
||||||
if (RuntimeInfo.Variables.ContainsKey(key))
|
|
||||||
{
|
|
||||||
RuntimeInfo.Variables[key] = parts[1].Trim();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RuntimeInfo.Variables.Add(key, parts[1].Trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RuntimeInfo.Exit("Invalid syntax");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[StaticStatement(ExecuteInSearchLabelMode = true)]
|
|
||||||
public void ReadVariable()
|
|
||||||
{
|
|
||||||
if (!RuntimeInfo.CurrentLine.Contains('>'))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (KeyValuePair<string, string> variable in RuntimeInfo.Variables)
|
|
||||||
{
|
|
||||||
RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{variable.Key}", variable.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
using YesNt.Interpreter.Attributes;
|
||||||
|
using YesNt.Interpreter.Enums;
|
||||||
|
using YesNt.Interpreter.Utilities;
|
||||||
|
|
||||||
|
namespace YesNt.Interpreter.Statements
|
||||||
|
{
|
||||||
|
internal class CodeFlowStatements : StatementRuntimeInformation
|
||||||
|
{
|
||||||
|
[Statement("jmp", SearchMode.StartOfLine, SpaceAround.End, Priority = Priority.VeryLow)]
|
||||||
|
public void Jump(string args)
|
||||||
|
{
|
||||||
|
string key = args.Trim();
|
||||||
|
|
||||||
|
if (RuntimeInfo.LabelStack.Count == 0 || RuntimeInfo.LabelStack.Peek() != RuntimeInfo.LineNumber)
|
||||||
|
{
|
||||||
|
RuntimeInfo.LabelStack.Push(RuntimeInfo.LineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuntimeInfo.Labels.ContainsKey(key))
|
||||||
|
{
|
||||||
|
RuntimeInfo.LineNumber = RuntimeInfo.Labels[key];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RuntimeInfo.SearchLabel = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("jif", SearchMode.StartOfLine, SpaceAround.End, Priority = Priority.VeryLow)]
|
||||||
|
public void JumpIf(string args)
|
||||||
|
{
|
||||||
|
string[] parts = args.Split('|');
|
||||||
|
if (parts.Length != 2)
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("Invalid syntax", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string key = parts[0].Trim();
|
||||||
|
string condition = parts[1].Trim();
|
||||||
|
|
||||||
|
bool? result = Evaluator.EvaluateCondition(condition);
|
||||||
|
|
||||||
|
if (result != true)
|
||||||
|
{
|
||||||
|
if (result is null)
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("Invalid operation", true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuntimeInfo.LabelStack.Count == 0 || RuntimeInfo.LabelStack.Peek() != RuntimeInfo.LineNumber)
|
||||||
|
{
|
||||||
|
RuntimeInfo.LabelStack.Push(RuntimeInfo.LineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuntimeInfo.Labels.ContainsKey(key))
|
||||||
|
{
|
||||||
|
RuntimeInfo.LineNumber = RuntimeInfo.Labels[key];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RuntimeInfo.SearchLabel = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("lbl", SearchMode.StartOfLine, SpaceAround.End, ExecuteInSearchLabelMode = true)]
|
||||||
|
public void FindLabel(string args)
|
||||||
|
{
|
||||||
|
string key = args.Trim();
|
||||||
|
if (RuntimeInfo.Labels.ContainsKey(key))
|
||||||
|
{
|
||||||
|
RuntimeInfo.Labels[key] = RuntimeInfo.LineNumber;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RuntimeInfo.Labels.Add(key, RuntimeInfo.LineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(RuntimeInfo.SearchLabel) && RuntimeInfo.SearchLabel == key)
|
||||||
|
{
|
||||||
|
RuntimeInfo.SearchLabel = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("ret", SearchMode.Exact, SpaceAround.None)]
|
||||||
|
public void Return(string _)
|
||||||
|
{
|
||||||
|
if (RuntimeInfo.LabelStack.Count > 0)
|
||||||
|
{
|
||||||
|
RuntimeInfo.LineNumber = RuntimeInfo.LabelStack.Pop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("No label in stack", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("end", SearchMode.Exact, SpaceAround.None)]
|
||||||
|
public void End(string _)
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("Planned termination by code", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("trm", SearchMode.Exact, SpaceAround.None)]
|
||||||
|
public void Terminate(string _)
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("Planned termination by code. Canceling all tasks", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
using YesNt.Interpreter.Attributes;
|
||||||
|
using YesNt.Interpreter.Enums;
|
||||||
|
using YesNt.Interpreter.Utilities;
|
||||||
|
|
||||||
|
namespace YesNt.Interpreter.Statements
|
||||||
|
{
|
||||||
|
internal class ConsoleStatements : StatementRuntimeInformation
|
||||||
|
{
|
||||||
|
[Statement("cwl", SearchMode.StartOfLine, SpaceAround.End, Priority = Priority.VeryLow)]
|
||||||
|
public void WriteLine(string args)
|
||||||
|
{
|
||||||
|
RuntimeInfo.WriteLine(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("cw", SearchMode.StartOfLine, SpaceAround.End, Priority = Priority.VeryLow)]
|
||||||
|
public void Write(string args)
|
||||||
|
{
|
||||||
|
RuntimeInfo.Write(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("%crl", SearchMode.Contains, SpaceAround.End, KeepStatementInArgs = true, Priority = Priority.Highest)]
|
||||||
|
public void ReadLine(string args)
|
||||||
|
{
|
||||||
|
args += " ";
|
||||||
|
while (args.Contains("%crl "))
|
||||||
|
{
|
||||||
|
string input = Console.ReadLine();
|
||||||
|
if (input is null)
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("Terminated by external process", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
args = args.ReplaceFirstOccurrence("%crl ", input.ToSaveString() + " ");
|
||||||
|
}
|
||||||
|
RuntimeInfo.CurrentLine = args.TrimEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("%cr", SearchMode.Contains, SpaceAround.End, KeepStatementInArgs = true, Priority = Priority.Highest)]
|
||||||
|
public void ReadKey(string args)
|
||||||
|
{
|
||||||
|
args += " ";
|
||||||
|
while (args.Contains("%cr "))
|
||||||
|
{
|
||||||
|
string input = ConsoleExtentions.ReadKey(RuntimeInfo).ToString();
|
||||||
|
args = args.ReplaceFirstOccurrence("%cr ", input.ToSaveString() + " ");
|
||||||
|
}
|
||||||
|
RuntimeInfo.CurrentLine = args.TrimEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using YesNt.Interpreter.Attributes;
|
||||||
|
using YesNt.Interpreter.Enums;
|
||||||
|
using YesNt.Interpreter.Utilities;
|
||||||
|
|
||||||
|
namespace YesNt.Interpreter.Statements
|
||||||
|
{
|
||||||
|
internal class ProcessingStatements : StatementRuntimeInformation
|
||||||
|
{
|
||||||
|
[Statement("!calc", SearchMode.EndOfLine, SpaceAround.Start, Priority = Priority.High, ExecuteInSearchLabelMode = true)]
|
||||||
|
public void Calculate(string args)
|
||||||
|
{
|
||||||
|
MatchCollection matches = Regex.Matches(args, @"((\)?)+(\(?)+[0-9]+(((\s?)+(\)?)(\s?)+\+(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\-(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\*(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\/(\s?)+(\(?)+(\s?)+)|[,.])(?=[0-9])+)+[0-9]+(\)?)+");
|
||||||
|
|
||||||
|
for (int i = 0; i < matches.Count; i++)
|
||||||
|
{
|
||||||
|
string res = Evaluator.Calculate(matches[i].Value);
|
||||||
|
if (res is null)
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("Invalid operation", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
args = args.Replace(matches[0].Value, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeInfo.CurrentLine = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("!eval", SearchMode.EndOfLine, SpaceAround.Start, Priority = Priority.VeryHigh)]
|
||||||
|
public void Evaluate(string args)
|
||||||
|
{
|
||||||
|
RuntimeInfo.CurrentLine = args.FromSaveString();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("!task", SearchMode.EndOfLine, SpaceAround.Start, Priority = Priority.VeryHigh)]
|
||||||
|
public void RunTask(string line)
|
||||||
|
{
|
||||||
|
int lineNumer = RuntimeInfo.LineNumber;
|
||||||
|
List<string> lines = RuntimeInfo.Lines.GetRange(0, RuntimeInfo.Lines.Count);
|
||||||
|
lines[lineNumer] = line;
|
||||||
|
_ = Task.Run(() =>
|
||||||
|
{
|
||||||
|
YesNtInterpreter interpreter = new YesNtInterpreter();
|
||||||
|
interpreter.Initialize();
|
||||||
|
interpreter.Execute(lines, lineNumer, RuntimeInfo);
|
||||||
|
});
|
||||||
|
|
||||||
|
RuntimeInfo.CurrentLine = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("slp", SearchMode.StartOfLine, SpaceAround.End)]
|
||||||
|
public void Sleep(string args)
|
||||||
|
{
|
||||||
|
_ = int.TryParse(args, out int millisecondsTimeout);
|
||||||
|
ConsoleExtentions.Sleep(millisecondsTimeout, RuntimeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("imp", SearchMode.StartOfLine, SpaceAround.End)]
|
||||||
|
public void Import(string path)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(Path.GetExtension(path)))
|
||||||
|
{
|
||||||
|
path = Path.ChangeExtension(path, "ynt");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RuntimeInfo.Lines.RemoveAt(0);
|
||||||
|
RuntimeInfo.Lines.InsertRange(RuntimeInfo.LineNumber, File.ReadAllLines(path));
|
||||||
|
RuntimeInfo.LineNumber--;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit($"Could not load file {path}", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit($"Could not find file {path}", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using YesNt.Interpreter.Attributes;
|
||||||
|
using YesNt.Interpreter.Enums;
|
||||||
|
|
||||||
|
namespace YesNt.Interpreter.Statements
|
||||||
|
{
|
||||||
|
internal class VariableStatements : StatementRuntimeInformation
|
||||||
|
{
|
||||||
|
[Statement("<", SearchMode.StartOfLine, SpaceAround.None, Priority = Priority.VeryLow, IgnoreSyntaxHighlighting = true)]
|
||||||
|
public void DefineVariable(string args)
|
||||||
|
{
|
||||||
|
string[] parts = args.Split('=');
|
||||||
|
if (parts.Length == 2)
|
||||||
|
{
|
||||||
|
string key = parts[0].Replace("<", "").Trim();
|
||||||
|
if (key.Contains(' '))
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("Invalid Syntax", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuntimeInfo.Variables.ContainsKey(key))
|
||||||
|
{
|
||||||
|
RuntimeInfo.Variables[key] = parts[1].Trim();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RuntimeInfo.Variables.Add(key, parts[1].Trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("Invalid syntax", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StaticStatement(ExecuteInSearchLabelMode = true)]
|
||||||
|
public void ReadVariable()
|
||||||
|
{
|
||||||
|
if (!RuntimeInfo.CurrentLine.Contains('>'))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, string> variable in RuntimeInfo.Variables)
|
||||||
|
{
|
||||||
|
RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{variable.Key}", variable.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace YesNt.Interpreter.Utilities
|
||||||
|
{
|
||||||
|
internal static class ConsoleExtentions
|
||||||
|
{
|
||||||
|
public static char ReadKey(RuntimeInformation runtimeInformation)
|
||||||
|
{
|
||||||
|
while (!runtimeInformation.Stop)
|
||||||
|
{
|
||||||
|
if (Console.KeyAvailable)
|
||||||
|
{
|
||||||
|
return Console.ReadKey().KeyChar;
|
||||||
|
}
|
||||||
|
Thread.Sleep(10);
|
||||||
|
}
|
||||||
|
return ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Sleep(int millisecondsTimeout, RuntimeInformation runtimeInformation)
|
||||||
|
{
|
||||||
|
Stopwatch stopwatch = new Stopwatch();
|
||||||
|
stopwatch.Start();
|
||||||
|
while (!runtimeInformation.Stop)
|
||||||
|
{
|
||||||
|
if (stopwatch.ElapsedMilliseconds > millisecondsTimeout)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Thread.Sleep(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -77,10 +77,6 @@ namespace YesNt.Interpreter.Utilities
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
((\)?)+(\(?)+[0-9]+(((\s?)+(\)?)(\s?)+\+(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\-(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\*(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\/(\s?)+(\(?)+(\s?)+)|[,.])(?=[0-9])+)+[0-9]+(\)?)+
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static string Calculate(string input, char op = '+')
|
public static string Calculate(string input, char op = '+')
|
||||||
{
|
{
|
||||||
if (input is null)
|
if (input is null)
|
||||||
|
|||||||
+44
-17
@@ -32,6 +32,7 @@ namespace YesNt.CodeEditor
|
|||||||
yesNtInterpreter.OnDebugOutput += YesNtInterpreter_OnDebugOutput;
|
yesNtInterpreter.OnDebugOutput += YesNtInterpreter_OnDebugOutput;
|
||||||
yesNtInterpreter.OnLineExecuted += YesNtInterpreter_OnLineExecuted;
|
yesNtInterpreter.OnLineExecuted += YesNtInterpreter_OnLineExecuted;
|
||||||
syntaxHighlighter = new(yesNtInterpreter.StatementInformation);
|
syntaxHighlighter = new(yesNtInterpreter.StatementInformation);
|
||||||
|
Console.CancelKeyPress += Console_CancelKeyPress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Run()
|
public void Run()
|
||||||
@@ -230,19 +231,32 @@ namespace YesNt.CodeEditor
|
|||||||
case "run":
|
case "run":
|
||||||
if (Save(input, true))
|
if (Save(input, true))
|
||||||
{
|
{
|
||||||
|
mode = Mode.Debug;
|
||||||
Console.Clear();
|
Console.Clear();
|
||||||
yesNtInterpreter.Execute(currentPath);
|
yesNtInterpreter.Execute(currentPath);
|
||||||
|
while (Console.KeyAvailable)
|
||||||
|
{
|
||||||
|
Console.ReadKey(true);
|
||||||
|
}
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
|
WriteStatus(string.Empty);
|
||||||
|
mode = Mode.Command;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "debug":
|
case "debug":
|
||||||
if (Save(input, true))
|
if (Save(input, true))
|
||||||
{
|
{
|
||||||
|
mode = Mode.Debug;
|
||||||
Console.Clear();
|
Console.Clear();
|
||||||
yesNtInterpreter.Execute(currentPath, true);
|
yesNtInterpreter.Execute(currentPath, true);
|
||||||
|
while (Console.KeyAvailable)
|
||||||
|
{
|
||||||
|
Console.ReadKey(true);
|
||||||
|
}
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
WriteStatus(string.Empty);
|
WriteStatus(string.Empty);
|
||||||
|
mode = Mode.Command;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -257,12 +271,6 @@ namespace YesNt.CodeEditor
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!File.Exists(path))
|
|
||||||
{
|
|
||||||
WriteStatus("File does not exist!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Load(path);
|
Load(path);
|
||||||
@@ -277,15 +285,13 @@ namespace YesNt.CodeEditor
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "new":
|
case "new":
|
||||||
if (Save(input, false))
|
|
||||||
{
|
lineOffset = 0;
|
||||||
lineOffset = 0;
|
cursorPosition.X = 0;
|
||||||
cursorPosition.X = 0;
|
cursorPosition.Y = 0;
|
||||||
cursorPosition.Y = 0;
|
currentPath = string.Empty;
|
||||||
currentPath = string.Empty;
|
lines.Clear();
|
||||||
lines.Clear();
|
WriteStatus(string.Empty);
|
||||||
WriteStatus(string.Empty);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "exit":
|
case "exit":
|
||||||
@@ -302,6 +308,11 @@ namespace YesNt.CodeEditor
|
|||||||
|
|
||||||
private bool Load(string path)
|
private bool Load(string path)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(Path.GetExtension(path)))
|
||||||
|
{
|
||||||
|
path = Path.ChangeExtension(path, "ynt");
|
||||||
|
}
|
||||||
|
|
||||||
if (!File.Exists(path))
|
if (!File.Exists(path))
|
||||||
{
|
{
|
||||||
WriteStatus("File does not exist!");
|
WriteStatus("File does not exist!");
|
||||||
@@ -321,7 +332,6 @@ namespace YesNt.CodeEditor
|
|||||||
private bool Save(string input, bool loadIfExists)
|
private bool Save(string input, bool loadIfExists)
|
||||||
{
|
{
|
||||||
string text = "";
|
string text = "";
|
||||||
string path = "";
|
|
||||||
|
|
||||||
foreach (string line in lines)
|
foreach (string line in lines)
|
||||||
{
|
{
|
||||||
@@ -329,6 +339,7 @@ namespace YesNt.CodeEditor
|
|||||||
}
|
}
|
||||||
text = text.TrimEnd('\n');
|
text = text.TrimEnd('\n');
|
||||||
|
|
||||||
|
string path;
|
||||||
if (input.Split(' ').Length == 2)
|
if (input.Split(' ').Length == 2)
|
||||||
{
|
{
|
||||||
path = input.Split(' ')[1];
|
path = input.Split(' ')[1];
|
||||||
@@ -361,6 +372,11 @@ namespace YesNt.CodeEditor
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(Path.GetExtension(path)))
|
||||||
|
{
|
||||||
|
path = Path.ChangeExtension(path, "ynt");
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.WriteAllText(path, text);
|
File.WriteAllText(path, text);
|
||||||
@@ -404,6 +420,16 @@ namespace YesNt.CodeEditor
|
|||||||
}
|
}
|
||||||
debugOutput.Clear();
|
debugOutput.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
|
||||||
|
{
|
||||||
|
e.Cancel = true;
|
||||||
|
if (mode == Mode.Debug)
|
||||||
|
{
|
||||||
|
yesNtInterpreter.Stop();
|
||||||
|
mode = Mode.Command;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class Point
|
internal class Point
|
||||||
@@ -421,6 +447,7 @@ namespace YesNt.CodeEditor
|
|||||||
internal enum Mode
|
internal enum Mode
|
||||||
{
|
{
|
||||||
Edit,
|
Edit,
|
||||||
Command
|
Command,
|
||||||
|
Debug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using System;
|
namespace YesNt.CodeEditor
|
||||||
|
|
||||||
namespace YesNt.CodeEditor
|
|
||||||
{
|
{
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
@@ -8,7 +6,6 @@ namespace YesNt.CodeEditor
|
|||||||
{
|
{
|
||||||
TextEditor textEditor;
|
TextEditor textEditor;
|
||||||
|
|
||||||
Console.CancelKeyPress += Console_CancelKeyPress;
|
|
||||||
if (args.Length > 0)
|
if (args.Length > 0)
|
||||||
{
|
{
|
||||||
textEditor = new TextEditor(args[0]);
|
textEditor = new TextEditor(args[0]);
|
||||||
@@ -20,10 +17,5 @@ namespace YesNt.CodeEditor
|
|||||||
|
|
||||||
textEditor.Run();
|
textEditor.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
|
|
||||||
{
|
|
||||||
e.Cancel = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user