From 3c98c2b26f8cb6de708c4299f7e2f1f284d2b558 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Thu, 28 Apr 2022 19:58:30 +0200
Subject: [PATCH 01/73] Code structure and speed imporvments
---
.../Runtime/RuntimeInformation.cs | 2 +-
.../PredifinedVariableStatements.cs | 35 +++++++++++++++----
.../Statements/VariableStatements.cs | 4 ++-
3 files changed, 32 insertions(+), 9 deletions(-)
diff --git a/YesNt.Interpreter/Runtime/RuntimeInformation.cs b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
index 0833eb0..9b5efc1 100644
--- a/YesNt.Interpreter/Runtime/RuntimeInformation.cs
+++ b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
@@ -6,7 +6,7 @@ using YesNt.Interpreter.Utilities;
namespace YesNt.Interpreter.Runtime
{
- internal class RuntimeInformation
+ internal sealed class RuntimeInformation
{
private RuntimeInformation parentRuntimeInformation;
private static int internalTaskId = 0;
diff --git a/YesNt.Interpreter/Statements/PredifinedVariableStatements.cs b/YesNt.Interpreter/Statements/PredifinedVariableStatements.cs
index 6974940..6740f44 100644
--- a/YesNt.Interpreter/Statements/PredifinedVariableStatements.cs
+++ b/YesNt.Interpreter/Statements/PredifinedVariableStatements.cs
@@ -11,13 +11,34 @@ namespace YesNt.Interpreter.Statements
{
private readonly Random random = new Random();
- [Statement("%tim", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ [Statement("%time", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void GetUnixTimestamp(string args)
{
- while (args.Contains("%tim"))
- {
- args = args.ReplaceFirstOccurrence("%tim", $"{DateTimeOffset.Now.ToUnixTimeSeconds()}");
- }
+ args = args.Replace("%time", DateTimeOffset.Now.ToUnixTimeSeconds().ToString());
+
+ RuntimeInfo.CurrentLine = args.TrimEnd();
+ }
+
+ [Statement("%os", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ public void GetOperatingSystem(string args)
+ {
+ args = args.Replace("%os", Environment.OSVersion.Platform.ToString());
+
+ RuntimeInfo.CurrentLine = args.TrimEnd();
+ }
+
+ [Statement("%cpu", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ public void GetProcessorArchitecture(string args)
+ {
+ args = args.Replace("%cpu", System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture.ToString());
+
+ RuntimeInfo.CurrentLine = args.TrimEnd();
+ }
+
+ [Statement("%is64", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ public void GetIsOperatingSystem64Bit(string args)
+ {
+ args = args.Replace("%is64", $"{Environment.Is64BitOperatingSystem}");
RuntimeInfo.CurrentLine = args.TrimEnd();
}
@@ -25,7 +46,7 @@ namespace YesNt.Interpreter.Statements
[Statement("%pi", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void GetPi(string args)
{
- args = args.Replace("%pi", $"{Math.PI}");
+ args = args.Replace("%pi", Math.PI.ToString());
RuntimeInfo.CurrentLine = args.TrimEnd();
}
@@ -35,7 +56,7 @@ namespace YesNt.Interpreter.Statements
{
while (args.Contains("%rnd"))
{
- args = args.ReplaceFirstOccurrence("%rnd", $"{random.Next(32767, int.MaxValue)}");
+ args = args.ReplaceFirstOccurrence("%rnd", random.Next(32767, int.MaxValue).ToString());
}
RuntimeInfo.CurrentLine = args.TrimEnd();
diff --git a/YesNt.Interpreter/Statements/VariableStatements.cs b/YesNt.Interpreter/Statements/VariableStatements.cs
index 8716075..3d2e48a 100644
--- a/YesNt.Interpreter/Statements/VariableStatements.cs
+++ b/YesNt.Interpreter/Statements/VariableStatements.cs
@@ -9,6 +9,8 @@ namespace YesNt.Interpreter.Statements
{
internal class VariableStatements : StatementRuntimeInformation
{
+ private static readonly Regex variableStatementRegex = new Regex(@">[a-zA-Z0-9]+");
+
[Statement("<", SearchMode.StartOfLine, SpaceAround.None, Priority = Priority.VeryLow)]
public void DefineVariable(string args)
{
@@ -105,7 +107,7 @@ namespace YesNt.Interpreter.Statements
return;
}
- MatchCollection matches = Regex.Matches(RuntimeInfo.CurrentLine, @">[a-zA-Z0-9]+");
+ MatchCollection matches = variableStatementRegex.Matches(RuntimeInfo.CurrentLine);
for (int i = 0; i < matches.Count; i++)
{
From dd6fbf3be773db1dd5d6fe942d7c7ca06189513c Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Tue, 24 May 2022 19:49:25 +0200
Subject: [PATCH 02/73] Add system statements ('exc')
---
.editorconfig | 3 +
YesNt-Interpreter.sln | 16 +-
.../Properties/launchSettings.json | 12 +
YesNt.CodeEditor/YesNt.CodeEditor.csproj | 1 +
.../YesNt.Interpreter.Tests.csproj | 2 +
.../Statements/SystemStatements.cs | 111 ++++++
YesNt.Interpreter/Utilities/FixedProcess.cs | 316 ++++++++++++++++++
YesNt.Interpreter/YesNt.Interpreter.csproj | 1 +
8 files changed, 461 insertions(+), 1 deletion(-)
create mode 100644 YesNt.CodeEditor/Properties/launchSettings.json
create mode 100644 YesNt.Interpreter/Statements/SystemStatements.cs
create mode 100644 YesNt.Interpreter/Utilities/FixedProcess.cs
diff --git a/.editorconfig b/.editorconfig
index 051cab7..0ec1ee4 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -64,6 +64,9 @@ dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
+# S1172: Unused method parameters should be removed
+dotnet_diagnostic.S1172.severity = none
+
[*.{cs,vb}]
#### Naming styles ####
diff --git a/YesNt-Interpreter.sln b/YesNt-Interpreter.sln
index ed6df67..0181ad5 100644
--- a/YesNt-Interpreter.sln
+++ b/YesNt-Interpreter.sln
@@ -12,26 +12,40 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YesNt.Interpreter.Tests", "YesNt.Interpreter.Tests\YesNt.Interpreter.Tests.csproj", "{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YesNt.Interpreter.Tests", "YesNt.Interpreter.Tests\YesNt.Interpreter.Tests.csproj", "{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Debug|x64.ActiveCfg = Debug|x64
+ {33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Debug|x64.Build.0 = Debug|x64
{33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Release|x64.ActiveCfg = Release|x64
+ {33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Release|x64.Build.0 = Release|x64
{E40573DB-912A-4871-BB65-3EE6E7D72E79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E40573DB-912A-4871-BB65-3EE6E7D72E79}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E40573DB-912A-4871-BB65-3EE6E7D72E79}.Debug|x64.ActiveCfg = Debug|x64
+ {E40573DB-912A-4871-BB65-3EE6E7D72E79}.Debug|x64.Build.0 = Debug|x64
{E40573DB-912A-4871-BB65-3EE6E7D72E79}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E40573DB-912A-4871-BB65-3EE6E7D72E79}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E40573DB-912A-4871-BB65-3EE6E7D72E79}.Release|x64.ActiveCfg = Release|x64
+ {E40573DB-912A-4871-BB65-3EE6E7D72E79}.Release|x64.Build.0 = Release|x64
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Debug|x64.ActiveCfg = Debug|x64
+ {2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Debug|x64.Build.0 = Debug|x64
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Release|x64.ActiveCfg = Release|x64
+ {2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/YesNt.CodeEditor/Properties/launchSettings.json b/YesNt.CodeEditor/Properties/launchSettings.json
new file mode 100644
index 0000000..161eba8
--- /dev/null
+++ b/YesNt.CodeEditor/Properties/launchSettings.json
@@ -0,0 +1,12 @@
+{
+ "profiles": {
+ "YesNt.CodeEditor": {
+ "commandName": "Project"
+ },
+ "WSL": {
+ "commandName": "WSL2",
+ "environmentVariables": {},
+ "distributionName": ""
+ }
+ }
+}
\ No newline at end of file
diff --git a/YesNt.CodeEditor/YesNt.CodeEditor.csproj b/YesNt.CodeEditor/YesNt.CodeEditor.csproj
index 68e1220..16be40b 100644
--- a/YesNt.CodeEditor/YesNt.CodeEditor.csproj
+++ b/YesNt.CodeEditor/YesNt.CodeEditor.csproj
@@ -3,6 +3,7 @@
Exe
net5.0
+ AnyCPU;x64
diff --git a/YesNt.Interpreter.Tests/YesNt.Interpreter.Tests.csproj b/YesNt.Interpreter.Tests/YesNt.Interpreter.Tests.csproj
index cf7cd15..9e6dacd 100644
--- a/YesNt.Interpreter.Tests/YesNt.Interpreter.Tests.csproj
+++ b/YesNt.Interpreter.Tests/YesNt.Interpreter.Tests.csproj
@@ -5,6 +5,8 @@
enable
false
+
+ AnyCPU;x64
diff --git a/YesNt.Interpreter/Statements/SystemStatements.cs b/YesNt.Interpreter/Statements/SystemStatements.cs
new file mode 100644
index 0000000..fb48103
--- /dev/null
+++ b/YesNt.Interpreter/Statements/SystemStatements.cs
@@ -0,0 +1,111 @@
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+
+using YesNt.Interpreter.Attributes;
+using YesNt.Interpreter.Enums;
+using YesNt.Interpreter.Runtime;
+using YesNt.Interpreter.Utilities;
+
+namespace YesNt.Interpreter.Statements
+{
+ internal class SystemStatements : StatementRuntimeInformation
+ {
+ [Statement("exc", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta, Priority = Priority.Low, Seperator = "|")]
+ public void ExecuteProgramWithArgs(string input)
+ {
+ string[] parts = input.FromSaveString().Split('|');
+ parts[0] = parts[0].Trim();
+
+ string[] functionArgumets = parts[1].Split(',');
+
+ foreach (string argumanet in functionArgumets)
+ {
+ RuntimeInfo.InParametersStack.Push(argumanet.Trim());
+ }
+
+ try
+ {
+ StartProcess(parts[0], string.Join(string.Empty, RuntimeInfo.InParametersStack.Reverse()));
+ }
+ catch (FileNotFoundException)
+ {
+ RuntimeInfo.Exit($"Cannot find file \"{parts[0]}\".", false);
+ }
+ catch (Win32Exception ex)
+ {
+ RuntimeInfo.Exit($"Failed to start \"{parts[0]}\". {ex.Message}", false);
+ }
+
+ //HACK: Clear line to avoid execution from other "exc" statement
+ RuntimeInfo.CurrentLine = string.Empty;
+ }
+
+ [Statement("exc", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta, Priority = Priority.VeryLow)]
+ public void ExecuteProgram(string input)
+ {
+ try
+ {
+ StartProcess(input, string.Join(string.Empty, RuntimeInfo.InParametersStack.Reverse()));
+ }
+ catch (FileNotFoundException)
+ {
+ RuntimeInfo.Exit($"Cannot find file \"{input}\".", false);
+ }
+ catch (Win32Exception ex)
+ {
+ RuntimeInfo.Exit($"Failed to start \"{input}\". {ex.Message}", false);
+ }
+ }
+
+ private void StartProcess(string name, string args)
+ {
+ FixedProcess process = new FixedProcess
+ {
+ StartInfo = new ProcessStartInfo()
+ {
+ FileName = name,
+ Arguments = args,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true
+ }
+ };
+
+ process.OutputDataReceived += Process_OutputDataReceived;
+ process.ErrorDataReceived += Process_ErrorDataReceived;
+
+ process.Start();
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+ process.WaitForExit();
+
+ RuntimeInfo.InParametersStack.Clear();
+ RuntimeInfo.OutParametersStack.Clear();
+ RuntimeInfo.OutParametersStack.Push(process.ExitCode.ToString());
+ }
+
+ private void Process_ErrorDataReceived(object sender, Utilities.DataReceivedEventArgs e)
+ {
+ if (string.IsNullOrWhiteSpace(e.Data))
+ {
+ return;
+ }
+
+ RuntimeInfo.OutParametersStack.Push(e.Data);
+ Console.Write("Error: " + e.Data);
+ }
+
+ private void Process_OutputDataReceived(object sender, Utilities.DataReceivedEventArgs e)
+ {
+ if (string.IsNullOrWhiteSpace(e.Data))
+ {
+ return;
+ }
+
+ RuntimeInfo.OutParametersStack.Push(e.Data);
+ Console.Write(e.Data);
+ }
+ }
+}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Utilities/FixedProcess.cs b/YesNt.Interpreter/Utilities/FixedProcess.cs
new file mode 100644
index 0000000..65a32e2
--- /dev/null
+++ b/YesNt.Interpreter/Utilities/FixedProcess.cs
@@ -0,0 +1,316 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using System.Threading;
+
+namespace YesNt.Interpreter.Utilities
+{
+ internal delegate void UserCallBack(string data);
+
+ public delegate void DataReceivedEventHandler(object sender, DataReceivedEventArgs e);
+
+ public class FixedProcess : Process
+ {
+ internal AsyncStreamReader output;
+ internal AsyncStreamReader error;
+
+ public new event DataReceivedEventHandler OutputDataReceived;
+
+ public new event DataReceivedEventHandler ErrorDataReceived;
+
+ public new void BeginOutputReadLine()
+ {
+ Stream baseStream = StandardOutput.BaseStream;
+ output = new AsyncStreamReader(this, baseStream, new UserCallBack(FixedOutputReadNotifyUser), StandardOutput.CurrentEncoding);
+ output.BeginReadLine();
+ }
+
+ public new void BeginErrorReadLine()
+ {
+ Stream baseStream = StandardError.BaseStream;
+ error = new AsyncStreamReader(this, baseStream, new UserCallBack(FixedErrorReadNotifyUser), StandardError.CurrentEncoding);
+ error.BeginReadLine();
+ }
+
+ internal void FixedOutputReadNotifyUser(string data)
+ {
+ DataReceivedEventHandler outputDataReceived = OutputDataReceived;
+ if (outputDataReceived != null)
+ {
+ DataReceivedEventArgs dataReceivedEventArgs = new DataReceivedEventArgs(data);
+ if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
+ {
+ SynchronizingObject.Invoke(outputDataReceived, new object[]
+ {
+ this,
+ dataReceivedEventArgs
+ });
+ return;
+ }
+ outputDataReceived(this, dataReceivedEventArgs);
+ }
+ }
+
+ internal void FixedErrorReadNotifyUser(string data)
+ {
+ DataReceivedEventHandler errorDataReceived = ErrorDataReceived;
+ if (errorDataReceived != null)
+ {
+ DataReceivedEventArgs dataReceivedEventArgs = new DataReceivedEventArgs(data);
+ if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
+ {
+ SynchronizingObject.Invoke(errorDataReceived, new object[]
+ {
+ this,
+ dataReceivedEventArgs
+ });
+ return;
+ }
+ errorDataReceived(this, dataReceivedEventArgs);
+ }
+ }
+ }
+
+ internal class AsyncStreamReader : IDisposable
+ {
+ internal const int DefaultBufferSize = 1024;
+ private Stream stream;
+ private Encoding encoding;
+ private Decoder decoder;
+ private byte[] byteBuffer;
+ private char[] charBuffer;
+ private UserCallBack userCallBack;
+ private bool cancelOperation;
+ private ManualResetEvent eofEvent;
+ private readonly Queue messageQueue;
+ private StringBuilder sb;
+ private bool bLastCarriageReturn;
+ public virtual Encoding CurrentEncoding => encoding;
+ public virtual Stream BaseStream => stream;
+
+ internal AsyncStreamReader(Process process, Stream stream, UserCallBack callback, Encoding encoding) : this(process, stream, callback, encoding, 1024)
+ {
+ }
+
+ internal AsyncStreamReader(Process process, Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
+ {
+ Init(process, stream, callback, encoding, bufferSize);
+ messageQueue = new Queue();
+ }
+
+ private void Init(Process process, Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
+ {
+ this.stream = stream;
+ this.encoding = encoding;
+ userCallBack = callback;
+ decoder = encoding.GetDecoder();
+ if (bufferSize < 128)
+ {
+ bufferSize = 128;
+ }
+ byteBuffer = new byte[bufferSize];
+ int _maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize);
+ charBuffer = new char[_maxCharsPerBuffer];
+ cancelOperation = false;
+ eofEvent = new ManualResetEvent(false);
+ sb = null;
+ bLastCarriageReturn = false;
+ }
+
+ public virtual void Close()
+ {
+ Dispose(true);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing && stream != null)
+ {
+ stream.Close();
+ }
+ if (stream != null)
+ {
+ stream = null;
+ encoding = null;
+ decoder = null;
+ byteBuffer = null;
+ charBuffer = null;
+ }
+ if (eofEvent != null)
+ {
+ eofEvent.Close();
+ eofEvent = null;
+ }
+ }
+
+ internal void BeginReadLine()
+ {
+ if (cancelOperation)
+ {
+ cancelOperation = false;
+ }
+ if (sb == null)
+ {
+ sb = new StringBuilder(1024);
+ stream.BeginRead(byteBuffer, 0, byteBuffer.Length, new AsyncCallback(ReadBuffer), null);
+ return;
+ }
+ FlushMessageQueue();
+ }
+
+ internal void CancelOperation()
+ {
+ cancelOperation = true;
+ }
+
+ private void ReadBuffer(IAsyncResult ar)
+ {
+ int num;
+ try
+ {
+ num = stream.EndRead(ar);
+ }
+ catch (IOException)
+ {
+ num = 0;
+ }
+ catch (OperationCanceledException)
+ {
+ num = 0;
+ }
+ if (num == 0)
+ {
+ lock (messageQueue)
+ {
+ if (sb.Length != 0)
+ {
+ messageQueue.Enqueue(sb.ToString());
+ sb.Length = 0;
+ }
+ messageQueue.Enqueue(null);
+ }
+ try
+ {
+ FlushMessageQueue();
+ return;
+ }
+ finally
+ {
+ eofEvent.Set();
+ }
+ }
+ int chars = decoder.GetChars(byteBuffer, 0, num, charBuffer, 0);
+ sb.Append(charBuffer, 0, chars);
+ GetLinesFromStringBuilder();
+ stream.BeginRead(byteBuffer, 0, byteBuffer.Length, new AsyncCallback(ReadBuffer), null);
+ }
+
+ private void GetLinesFromStringBuilder()
+ {
+ int i = 0;
+ int num = 0;
+ int length = sb.Length;
+ if (bLastCarriageReturn && length > 0 && sb[0] == '\n')
+ {
+ i = 1;
+ num = 1;
+ bLastCarriageReturn = false;
+ }
+ while (i < length)
+ {
+ char c = sb[i];
+ if (c == '\r' || c == '\n')
+ {
+ if (c == '\r' && i + 1 < length && sb[i + 1] == '\n')
+ {
+ i++;
+ }
+
+ string obj = sb.ToString(num, i + 1 - num);
+
+ num = i + 1;
+
+ lock (messageQueue)
+ {
+ messageQueue.Enqueue(obj);
+ }
+ }
+ i++;
+ }
+
+ // Flush Fix: Send Whatever is left in the buffer
+ string endOfBuffer = sb.ToString(num, length - num);
+ lock (messageQueue)
+ {
+ messageQueue.Enqueue(endOfBuffer);
+ num = length;
+ }
+ // End Flush Fix
+
+ if (sb[length - 1] == '\r')
+ {
+ bLastCarriageReturn = true;
+ }
+ if (num < length)
+ {
+ sb.Remove(0, num);
+ }
+ else
+ {
+ sb.Length = 0;
+ }
+ FlushMessageQueue();
+ }
+
+ private void FlushMessageQueue()
+ {
+ while (messageQueue.Count > 0)
+ {
+ lock (messageQueue)
+ {
+ if (messageQueue.Count > 0)
+ {
+ string data = (string)messageQueue.Dequeue();
+ if (!cancelOperation)
+ {
+ userCallBack(data);
+ }
+ }
+ }
+ }
+ }
+
+ internal void WaitUtilEOF()
+ {
+ if (eofEvent != null)
+ {
+ eofEvent.WaitOne();
+ eofEvent.Close();
+ eofEvent = null;
+ }
+ }
+ }
+
+ public class DataReceivedEventArgs : EventArgs
+ {
+ internal string _data;
+
+ /// Gets the line of characters that was written to a redirected output stream.
+ /// The line that was written by an associated to its redirected or stream.
+ /// 2
+ public string Data => _data;
+
+ internal DataReceivedEventArgs(string data)
+ {
+ _data = data;
+ }
+ }
+}
\ No newline at end of file
diff --git a/YesNt.Interpreter/YesNt.Interpreter.csproj b/YesNt.Interpreter/YesNt.Interpreter.csproj
index c017137..bd4ef12 100644
--- a/YesNt.Interpreter/YesNt.Interpreter.csproj
+++ b/YesNt.Interpreter/YesNt.Interpreter.csproj
@@ -6,6 +6,7 @@
Exe
+ AnyCPU;x64
From 533ad23c4da8187ce0a1869d88a738eda59888c8 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Thu, 17 Nov 2022 09:29:29 +0100
Subject: [PATCH 03/73] Fix error when loading empty file
---
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 29 ++++++++++---------
1 file changed, 16 insertions(+), 13 deletions(-)
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index 1b89015..ce07f9b 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -94,8 +94,10 @@ namespace YesNt.Interpreter.Runtime
{
runtimeInfo.Reset();
runtimeInfo.IsDebugMode = isDebugMode;
- LoadFile(path);
- Execute();
+ if (LoadFile(path))
+ {
+ Execute();
+ }
}
public void Execute(List lines, bool isDebugMode = false)
@@ -205,14 +207,7 @@ namespace YesNt.Interpreter.Runtime
statement.Value.Invoke(copyLine);
statementFound = true;
- if (!leadingWhitespace)
- {
- runtimeInfo.CurrentLine = runtimeInfo.CurrentLine.Trim();
- }
- else
- {
- runtimeInfo.CurrentLine = runtimeInfo.CurrentLine.TrimEnd();
- }
+ runtimeInfo.CurrentLine = !leadingWhitespace ? runtimeInfo.CurrentLine.Trim() : runtimeInfo.CurrentLine.TrimEnd();
}
else if (statementAttribute.SearchMode == SearchMode.EndOfLine && runtimeInfo.CurrentLine.EndsWith(name))
{
@@ -261,20 +256,28 @@ namespace YesNt.Interpreter.Runtime
}
}
- private void LoadFile(string path)
+ private bool LoadFile(string path)
{
if (!File.Exists(path))
{
- runtimeInfo.Exit($"File \"{path}\" not found!", true);
- return;
+ Console.WriteLine($"File \"{path}\" not found!");
+ return false;
}
string[] lines = File.ReadAllLines(path);
+ if (lines.Length <= 0)
+ {
+ Console.WriteLine($"File \"{path}\" is empty!");
+ return false;
+ }
+
for (int i = 0; i < lines.Length; i++)
{
runtimeInfo.Lines.Add(new Line(lines[i], Path.GetFileName(path), i));
}
+
+ return true;
}
}
}
\ No newline at end of file
From 1ced6f393c9d8c93ae5570d9592fb4a139db212f Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Thu, 17 Nov 2022 11:40:51 +0100
Subject: [PATCH 04/73] Improve code formatting
---
YesNt.CodeEditor/Editor.cs | 11 +----
YesNt.CodeEditor/InputHandler.cs | 25 +++++-------
YesNt.CodeEditor/Program.cs | 12 +-----
YesNt.Interpreter.Tests/CodeFowTests.cs | 2 +-
YesNt.Interpreter.Tests/YesNtAssert.cs | 4 +-
.../Runtime/RuntimeInformation.cs | 40 ++++---------------
.../Statements/SystemStatements.cs | 2 +-
.../Statements/VariableStatements.cs | 4 +-
YesNt.Interpreter/Utilities/Evaluator.cs | 28 ++-----------
YesNt.Interpreter/Utilities/FixedProcess.cs | 18 ++++-----
.../Utilities/StringExtentions.cs | 2 +-
11 files changed, 39 insertions(+), 109 deletions(-)
diff --git a/YesNt.CodeEditor/Editor.cs b/YesNt.CodeEditor/Editor.cs
index dee06c7..54c92cb 100644
--- a/YesNt.CodeEditor/Editor.cs
+++ b/YesNt.CodeEditor/Editor.cs
@@ -23,7 +23,7 @@ namespace YesNt.CodeEditor
{
if (File.Exists(path))
{
- Load(path);
+ _ = Load(path);
}
}
@@ -131,14 +131,7 @@ namespace YesNt.CodeEditor
if (CurrentPath.Trim() != path.Trim() && loadIfExists)
{
- if (Load(path))
- {
- return true;
- }
- else
- {
- return false;
- }
+ return Load(path);
}
if (string.IsNullOrEmpty(Path.GetExtension(path)))
{
diff --git a/YesNt.CodeEditor/InputHandler.cs b/YesNt.CodeEditor/InputHandler.cs
index 59a3024..3b31f46 100644
--- a/YesNt.CodeEditor/InputHandler.cs
+++ b/YesNt.CodeEditor/InputHandler.cs
@@ -16,7 +16,7 @@ namespace YesNt.CodeEditor
{
while (Console.KeyAvailable)
{
- Console.ReadKey(true);
+ _ = Console.ReadKey(true);
}
if (textEditor.EditMode == Mode.Edit)
{
@@ -50,14 +50,7 @@ namespace YesNt.CodeEditor
return true;
case ConsoleKey.E:
- if (textEditor.Lines.Count > textEditor.CursorPosition.Y)
- {
- textEditor.CursorPosition.X = textEditor.Lines[textEditor.CursorPosition.Y].TrimEnd().Length;
- }
- else
- {
- textEditor.CursorPosition.X = 0;
- }
+ textEditor.CursorPosition.X = textEditor.Lines.Count > textEditor.CursorPosition.Y ? textEditor.Lines[textEditor.CursorPosition.Y].TrimEnd().Length : 0;
return true;
}
}
@@ -128,7 +121,7 @@ namespace YesNt.CodeEditor
StringBuilder lineBuilder = new StringBuilder(textEditor.Lines[textEditor.CursorPosition.Y]);
while (lineBuilder.Length <= textEditor.CursorPosition.X)
{
- lineBuilder.Append(' ');
+ _ = lineBuilder.Append(' ');
}
textEditor.Lines[textEditor.CursorPosition.Y] = lineBuilder.ToString();
@@ -228,7 +221,7 @@ namespace YesNt.CodeEditor
break;
case "save":
- textEditor.Save(input, false);
+ _ = textEditor.Save(input, false);
break;
case "run":
@@ -240,9 +233,9 @@ namespace YesNt.CodeEditor
textEditor.YesNtInterpreter.Execute(textEditor.CurrentPath);
while (Console.KeyAvailable)
{
- Console.ReadKey(true);
+ _ = Console.ReadKey(true);
}
- Console.ReadKey();
+ _ = Console.ReadKey();
WriteStatus(string.Empty);
textEditor.EditMode = Mode.Command;
}
@@ -257,9 +250,9 @@ namespace YesNt.CodeEditor
textEditor.YesNtInterpreter.Execute(textEditor.CurrentPath, true);
while (Console.KeyAvailable)
{
- Console.ReadKey(true);
+ _ = Console.ReadKey(true);
}
- Console.ReadKey();
+ _ = Console.ReadKey();
WriteStatus(string.Empty);
textEditor.EditMode = Mode.Command;
}
@@ -278,7 +271,7 @@ namespace YesNt.CodeEditor
try
{
- textEditor.Load(path);
+ _ = textEditor.Load(path);
}
catch (Exception ex)
{
diff --git a/YesNt.CodeEditor/Program.cs b/YesNt.CodeEditor/Program.cs
index d95b4a7..ffa8ec7 100644
--- a/YesNt.CodeEditor/Program.cs
+++ b/YesNt.CodeEditor/Program.cs
@@ -4,17 +4,7 @@
{
private static void Main(string[] args)
{
- TextEditor textEditor;
-
- if (args.Length > 0)
- {
- textEditor = new TextEditor(args[0]);
- }
- else
- {
- textEditor = new TextEditor();
- }
-
+ TextEditor textEditor = args.Length > 0 ? new TextEditor(args[0]) : new TextEditor();
textEditor.Run();
}
}
diff --git a/YesNt.Interpreter.Tests/CodeFowTests.cs b/YesNt.Interpreter.Tests/CodeFowTests.cs
index 105b253..23a715a 100644
--- a/YesNt.Interpreter.Tests/CodeFowTests.cs
+++ b/YesNt.Interpreter.Tests/CodeFowTests.cs
@@ -39,6 +39,6 @@ public class CodeFlowTests
public void CalculationsTest()
{
Assert.Inconclusive();
- YesNtAssert.IsLineEqual("10 * 10 !calc", (20).ToString());
+ YesNtAssert.IsLineEqual("10 * 10 !calc", 20.ToString());
}
}
\ No newline at end of file
diff --git a/YesNt.Interpreter.Tests/YesNtAssert.cs b/YesNt.Interpreter.Tests/YesNtAssert.cs
index e7ae5f7..b7200a6 100644
--- a/YesNt.Interpreter.Tests/YesNtAssert.cs
+++ b/YesNt.Interpreter.Tests/YesNtAssert.cs
@@ -28,7 +28,7 @@ internal static class YesNtAssert
if (er is null)
{
- onDone.Set();
+ _ = onDone.Set();
}
};
@@ -51,7 +51,7 @@ internal static class YesNtAssert
yesNtInterpreter.OnLineExecuted += (er) =>
{
debugEventArgs = er ?? debugEventArgs;
- onDone.Set();
+ _ = onDone.Set();
};
yesNtInterpreter.Execute(lines, true);
diff --git a/YesNt.Interpreter/Runtime/RuntimeInformation.cs b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
index 9b5efc1..8113c6b 100644
--- a/YesNt.Interpreter/Runtime/RuntimeInformation.cs
+++ b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
@@ -28,7 +28,7 @@ namespace YesNt.Interpreter.Runtime
public bool Stop { get; private set; } = false;
public bool StopAllTasks { get; private set; } = false;
public bool IsDebugMode { get; set; } = false;
- public string CurrentFilePath { get; set; } = string.Empty;
+ public string WorkingDirectory { get; set; } = string.Empty;
public bool IsTask => ParentRuntimeInformation is not null;
public int TaskId => IsTask ? taskId : 0;
public bool InternalIsInFunction { get; set; }
@@ -39,35 +39,9 @@ namespace YesNt.Interpreter.Runtime
set => InternalIsInFunction = value;
}
- public Dictionary Variables
- {
- get
- {
- if (FunctionCallStack.Count == 0)
- {
- return topVariables;
- }
- else
- {
- return FunctionCallStack.Peek().Variables;
- }
- }
- }
+ public Dictionary Variables => FunctionCallStack.Count == 0 ? topVariables : FunctionCallStack.Peek().Variables;
- public Dictionary Labels
- {
- get
- {
- if (FunctionCallStack.Count == 0)
- {
- return topLabels;
- }
- else
- {
- return FunctionCallStack.Peek().Labels;
- }
- }
- }
+ public Dictionary Labels => FunctionCallStack.Count == 0 ? topLabels : FunctionCallStack.Peek().Labels;
public RuntimeInformation ParentRuntimeInformation
{
@@ -82,7 +56,7 @@ namespace YesNt.Interpreter.Runtime
}
}
- public bool IsSearching => !string.IsNullOrWhiteSpace(SearchLabel + SearchFunction) || IsInFunction && FunctionCallStack.Count == 0;
+ public bool IsSearching => !string.IsNullOrWhiteSpace(SearchLabel + SearchFunction) || (IsInFunction && FunctionCallStack.Count == 0);
public bool IsLocalSearch { get; set; }
private event Action OnExit;
@@ -98,7 +72,7 @@ namespace YesNt.Interpreter.Runtime
public void WriteLine(string output, bool forceWrite = false)
{
- if (Stop && !forceWrite || parentRuntimeInformation?.StopAllTasks == true && !forceWrite)
+ if ((Stop && !forceWrite) || (parentRuntimeInformation?.StopAllTasks == true && !forceWrite))
{
return;
}
@@ -122,7 +96,7 @@ namespace YesNt.Interpreter.Runtime
public void Write(string output, bool forceWrite = false)
{
- if (Stop && !forceWrite || parentRuntimeInformation?.StopAllTasks == true && !forceWrite)
+ if ((Stop && !forceWrite) || (parentRuntimeInformation?.StopAllTasks == true && !forceWrite))
{
return;
}
@@ -190,7 +164,7 @@ namespace YesNt.Interpreter.Runtime
ParentRuntimeInformation = null;
SearchLabel = string.Empty;
SearchFunction = string.Empty;
- CurrentFilePath = string.Empty;
+ WorkingDirectory = string.Empty;
CurrentLine = string.Empty;
Stop = false;
StopAllTasks = false;
diff --git a/YesNt.Interpreter/Statements/SystemStatements.cs b/YesNt.Interpreter/Statements/SystemStatements.cs
index fb48103..ac357b7 100644
--- a/YesNt.Interpreter/Statements/SystemStatements.cs
+++ b/YesNt.Interpreter/Statements/SystemStatements.cs
@@ -76,7 +76,7 @@ namespace YesNt.Interpreter.Statements
process.OutputDataReceived += Process_OutputDataReceived;
process.ErrorDataReceived += Process_ErrorDataReceived;
- process.Start();
+ _ = process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
diff --git a/YesNt.Interpreter/Statements/VariableStatements.cs b/YesNt.Interpreter/Statements/VariableStatements.cs
index 3d2e48a..06194a2 100644
--- a/YesNt.Interpreter/Statements/VariableStatements.cs
+++ b/YesNt.Interpreter/Statements/VariableStatements.cs
@@ -72,11 +72,11 @@ namespace YesNt.Interpreter.Statements
if (RuntimeInfo.Variables.ContainsKey(key))
{
- RuntimeInfo.Variables.Remove(key);
+ _ = RuntimeInfo.Variables.Remove(key);
}
else if (RuntimeInfo.GloablVariables.ContainsKey(key))
{
- RuntimeInfo.GloablVariables.Remove(key);
+ _ = RuntimeInfo.GloablVariables.Remove(key);
}
else
{
diff --git a/YesNt.Interpreter/Utilities/Evaluator.cs b/YesNt.Interpreter/Utilities/Evaluator.cs
index 1f0f239..aac7d50 100644
--- a/YesNt.Interpreter/Utilities/Evaluator.cs
+++ b/YesNt.Interpreter/Utilities/Evaluator.cs
@@ -38,12 +38,7 @@ namespace YesNt.Interpreter.Utilities
{
bool succ1 = parts[0].ToStandardizedNumber(out double part1);
bool succ2 = parts[1].ToStandardizedNumber(out double part2);
- if (!succ1 || !succ2)
- {
- return false;
- }
-
- return part1 >= part2;
+ return succ1 && succ2 && part1 >= part2;
}
parts = input.Split("<=");
@@ -51,12 +46,7 @@ namespace YesNt.Interpreter.Utilities
{
bool succ1 = parts[0].ToStandardizedNumber(out double part1);
bool succ2 = parts[1].ToStandardizedNumber(out double part2);
- if (!succ1 || !succ2)
- {
- return false;
- }
-
- return part1 <= part2;
+ return succ1 && succ2 && part1 <= part2;
}
parts = input.Split(">");
@@ -64,12 +54,7 @@ namespace YesNt.Interpreter.Utilities
{
bool succ1 = parts[0].ToStandardizedNumber(out double part1);
bool succ2 = parts[1].ToStandardizedNumber(out double part2);
- if (!succ1 || !succ2)
- {
- return false;
- }
-
- return part1 > part2;
+ return succ1 && succ2 && part1 > part2;
}
parts = input.Split("<");
@@ -77,12 +62,7 @@ namespace YesNt.Interpreter.Utilities
{
bool succ1 = parts[0].ToStandardizedNumber(out double part1);
bool succ2 = parts[1].ToStandardizedNumber(out double part2);
- if (!succ1 || !succ2)
- {
- return false;
- }
-
- return part1 < part2;
+ return succ1 && succ2 && part1 < part2;
}
return null;
diff --git a/YesNt.Interpreter/Utilities/FixedProcess.cs b/YesNt.Interpreter/Utilities/FixedProcess.cs
index 65a32e2..9ee542d 100644
--- a/YesNt.Interpreter/Utilities/FixedProcess.cs
+++ b/YesNt.Interpreter/Utilities/FixedProcess.cs
@@ -42,7 +42,7 @@ namespace YesNt.Interpreter.Utilities
DataReceivedEventArgs dataReceivedEventArgs = new DataReceivedEventArgs(data);
if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
{
- SynchronizingObject.Invoke(outputDataReceived, new object[]
+ _ = SynchronizingObject.Invoke(outputDataReceived, new object[]
{
this,
dataReceivedEventArgs
@@ -61,7 +61,7 @@ namespace YesNt.Interpreter.Utilities
DataReceivedEventArgs dataReceivedEventArgs = new DataReceivedEventArgs(data);
if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
{
- SynchronizingObject.Invoke(errorDataReceived, new object[]
+ _ = SynchronizingObject.Invoke(errorDataReceived, new object[]
{
this,
dataReceivedEventArgs
@@ -160,7 +160,7 @@ namespace YesNt.Interpreter.Utilities
if (sb == null)
{
sb = new StringBuilder(1024);
- stream.BeginRead(byteBuffer, 0, byteBuffer.Length, new AsyncCallback(ReadBuffer), null);
+ _ = stream.BeginRead(byteBuffer, 0, byteBuffer.Length, new AsyncCallback(ReadBuffer), null);
return;
}
FlushMessageQueue();
@@ -204,13 +204,13 @@ namespace YesNt.Interpreter.Utilities
}
finally
{
- eofEvent.Set();
+ _ = eofEvent.Set();
}
}
int chars = decoder.GetChars(byteBuffer, 0, num, charBuffer, 0);
- sb.Append(charBuffer, 0, chars);
+ _ = sb.Append(charBuffer, 0, chars);
GetLinesFromStringBuilder();
- stream.BeginRead(byteBuffer, 0, byteBuffer.Length, new AsyncCallback(ReadBuffer), null);
+ _ = stream.BeginRead(byteBuffer, 0, byteBuffer.Length, new AsyncCallback(ReadBuffer), null);
}
private void GetLinesFromStringBuilder()
@@ -227,7 +227,7 @@ namespace YesNt.Interpreter.Utilities
while (i < length)
{
char c = sb[i];
- if (c == '\r' || c == '\n')
+ if (c is '\r' or '\n')
{
if (c == '\r' && i + 1 < length && sb[i + 1] == '\n')
{
@@ -261,7 +261,7 @@ namespace YesNt.Interpreter.Utilities
}
if (num < length)
{
- sb.Remove(0, num);
+ _ = sb.Remove(0, num);
}
else
{
@@ -292,7 +292,7 @@ namespace YesNt.Interpreter.Utilities
{
if (eofEvent != null)
{
- eofEvent.WaitOne();
+ _ = eofEvent.WaitOne();
eofEvent.Close();
eofEvent = null;
}
diff --git a/YesNt.Interpreter/Utilities/StringExtentions.cs b/YesNt.Interpreter/Utilities/StringExtentions.cs
index 6c81400..c8e615e 100644
--- a/YesNt.Interpreter/Utilities/StringExtentions.cs
+++ b/YesNt.Interpreter/Utilities/StringExtentions.cs
@@ -11,7 +11,7 @@ namespace YesNt.Interpreter.Utilities
StringBuilder output = new StringBuilder();
foreach (char c in input)
{
- output.Append($"\v{c}\v");
+ _ = output.Append($"\v{c}\v");
}
return output.ToString();
}
From e5398133144b3c06866e57208054cbabf6fece9b Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Thu, 17 Nov 2022 11:54:01 +0100
Subject: [PATCH 05/73] Use correct directory when importing other file
---
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 4 ++++
YesNt.Interpreter/Statements/ProcessingStatements.cs | 2 ++
2 files changed, 6 insertions(+)
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index ce07f9b..7445996 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -258,6 +258,8 @@ namespace YesNt.Interpreter.Runtime
private bool LoadFile(string path)
{
+ path = Path.GetFullPath(path);
+
if (!File.Exists(path))
{
Console.WriteLine($"File \"{path}\" not found!");
@@ -272,6 +274,8 @@ namespace YesNt.Interpreter.Runtime
return false;
}
+ runtimeInfo.WorkingDirectory = Path.GetDirectoryName(path);
+
for (int i = 0; i < lines.Length; i++)
{
runtimeInfo.Lines.Add(new Line(lines[i], Path.GetFileName(path), i));
diff --git a/YesNt.Interpreter/Statements/ProcessingStatements.cs b/YesNt.Interpreter/Statements/ProcessingStatements.cs
index 282bcad..5efe797 100644
--- a/YesNt.Interpreter/Statements/ProcessingStatements.cs
+++ b/YesNt.Interpreter/Statements/ProcessingStatements.cs
@@ -86,6 +86,8 @@ namespace YesNt.Interpreter.Statements
[Statement("imp", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
public void Import(string path)
{
+ path = Path.Combine(RuntimeInfo.WorkingDirectory, path);
+
if (string.IsNullOrEmpty(Path.GetExtension(path)))
{
path = Path.ChangeExtension(path, "ynt");
From 0f7f63ae9a3e74fc6ffe08829e9e09d94f4e842e Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Thu, 17 Nov 2022 12:37:32 +0100
Subject: [PATCH 06/73] Improve Regex performance and change .NET version to
.NET 7
---
YesNt.CodeEditor/SyntaxHighlighter.cs | 244 +++++++-------
YesNt.CodeEditor/YesNt.CodeEditor.csproj | 2 +-
.../YesNt.Interpreter.Tests.csproj | 2 +-
.../Statements/ProcessingStatements.cs | 188 +++++------
.../Statements/VariableStatements.cs | 192 +++++------
YesNt.Interpreter/Utilities/Evaluator.cs | 300 +++++++++---------
YesNt.Interpreter/Utilities/FixedProcess.cs | 12 +-
YesNt.Interpreter/YesNt.Interpreter.csproj | 2 +-
8 files changed, 485 insertions(+), 457 deletions(-)
diff --git a/YesNt.CodeEditor/SyntaxHighlighter.cs b/YesNt.CodeEditor/SyntaxHighlighter.cs
index d85fc6b..b69420d 100644
--- a/YesNt.CodeEditor/SyntaxHighlighter.cs
+++ b/YesNt.CodeEditor/SyntaxHighlighter.cs
@@ -6,154 +6,168 @@ using YesNt.Interpreter.Enums;
using YesNt.Interpreter.Runtime;
using YesNt.Interpreter.Utilities;
-namespace YesNt.CodeEditor
+namespace YesNt.CodeEditor;
+
+internal partial class SyntaxHighlighter
{
- internal class SyntaxHighlighter
+ private readonly ReadOnlyCollection statementInformation;
+
+ public SyntaxHighlighter(ReadOnlyCollection statementInformation)
{
- private readonly ReadOnlyCollection statementInformation;
+ this.statementInformation = statementInformation;
+ }
- public SyntaxHighlighter(ReadOnlyCollection statementInformation)
+ public void Write(string input)
+ {
+ input = input.Replace("\0", string.Empty);
+
+ if (input.StartsWith('#'))
{
- this.statementInformation = statementInformation;
+ input = AddColorInformation(input, input, ConsoleColor.Gray, SearchMode.Exact);
}
-
- public void Write(string input)
+ else
{
- input = input.Replace("\0", string.Empty);
-
- if (input.StartsWith('#'))
+ MatchCollection matches = EscapeSequenceRegex().Matches(input);
+ for (int i = 0; i < matches.Count; i++)
{
- input = AddColorInformation(input, input, ConsoleColor.Gray, SearchMode.Exact);
+ input = AddColorInformation(input, matches[i].Value, Console.ForegroundColor, SearchMode.Contains);
}
- else
+
+ foreach (StatementInformation statement in statementInformation)
{
- MatchCollection matches = Regex.Matches(input, @"!!.");
- for (int i = 0; i < matches.Count; i++)
+ if (statement.IgnoreSyntaxHighlighting)
{
- input = AddColorInformation(input, matches[i].Value, Console.ForegroundColor, SearchMode.Contains);
+ continue;
}
- foreach (StatementInformation statement in statementInformation)
+ string name = statement.SpaceAround switch
{
- if (statement.IgnoreSyntaxHighlighting)
+ SpaceAround.StartEnd => $" {statement.Name.Trim()} ",
+ SpaceAround.Start => $" {statement.Name.Trim()}",
+ SpaceAround.End => $"{statement.Name.Trim()} ",
+ _ => statement.Name
+ };
+ input = input.TrimEnd();
+ if (statement.SearchMode == SearchMode.StartOfLine && input.StartsWith(name))
+ {
+ if (statement.Seperator is not null && input.Contains(statement.Seperator))
+ {
+ input = AddColorInformation(input, statement.Seperator, statement.Color, SearchMode.StartOfLine);
+ }
+ else if (statement.Seperator is not null)
{
continue;
}
-
- string name = statement.SpaceAround switch
- {
- SpaceAround.StartEnd => $" {statement.Name.Trim()} ",
- SpaceAround.Start => $" {statement.Name.Trim()}",
- SpaceAround.End => $"{statement.Name.Trim()} ",
- _ => statement.Name
- };
- input = input.TrimEnd();
- if (statement.SearchMode == SearchMode.StartOfLine && input.StartsWith(name))
- {
- if (statement.Seperator is not null && input.Contains(statement.Seperator))
- {
- input = AddColorInformation(input, statement.Seperator, statement.Color, SearchMode.StartOfLine);
- }
- else if (statement.Seperator is not null)
- {
- continue;
- }
- input = AddColorInformation(input, input[..name.Length], statement.Color, statement.SearchMode);
- }
- if (statement.SearchMode == SearchMode.Contains && $" {input} ".Contains(name))
- {
- if (statement.Seperator is not null && input.Contains(statement.Seperator))
- {
- input = AddColorInformation(input, statement.Seperator, statement.Color, SearchMode.StartOfLine);
- }
- else if (statement.Seperator is not null)
- {
- continue;
- }
- input = AddColorInformation($"{input} ", $"{input} ".Substring($"{input} ".IndexOf(name), name.Length), statement.Color, statement.SearchMode);
- }
- if (statement.SearchMode == SearchMode.EndOfLine && input.EndsWith(name))
- {
- if (statement.Seperator is not null && input.Contains(statement.Seperator))
- {
- input = AddColorInformation(input, statement.Seperator, statement.Color, SearchMode.StartOfLine);
- }
- else if (statement.Seperator is not null)
- {
- continue;
- }
- input = AddColorInformation(input, input[^name.Length..], statement.Color, statement.SearchMode);
- }
- if (statement.SearchMode == SearchMode.Exact && input.Equals(name))
- {
- if (statement.Seperator is not null && input.Contains(statement.Seperator))
- {
- input = AddColorInformation(input, statement.Seperator, statement.Color, SearchMode.StartOfLine);
- }
- else if (statement.Seperator is not null)
- {
- continue;
- }
- input = AddColorInformation(input, input, statement.Color, statement.SearchMode);
- }
+ input = AddColorInformation(input, input[..name.Length], statement.Color, statement.SearchMode);
}
-
- matches = Regex.Matches(input, @">[a-zA-Z0-9]+");
- for (int i = 0; i < matches.Count; i++)
+ if (statement.SearchMode == SearchMode.Contains && $" {input} ".Contains(name))
{
- input = AddColorInformation(input, matches[i].Value, ConsoleColor.Cyan, SearchMode.Contains);
+ if (statement.Seperator is not null && input.Contains(statement.Seperator))
+ {
+ input = AddColorInformation(input, statement.Seperator, statement.Color, SearchMode.StartOfLine);
+ }
+ else if (statement.Seperator is not null)
+ {
+ continue;
+ }
+ input = AddColorInformation($"{input} ", $"{input} ".Substring($"{input} ".IndexOf(name), name.Length), statement.Color, statement.SearchMode);
}
-
- matches = Regex.Matches(input, @"^<[a-zA-Z0-9]+");
- for (int i = 0; i < matches.Count; i++)
+ if (statement.SearchMode == SearchMode.EndOfLine && input.EndsWith(name))
{
- input = AddColorInformation(input, matches[i].Value, ConsoleColor.DarkCyan, SearchMode.StartOfLine);
+ if (statement.Seperator is not null && input.Contains(statement.Seperator))
+ {
+ input = AddColorInformation(input, statement.Seperator, statement.Color, SearchMode.StartOfLine);
+ }
+ else if (statement.Seperator is not null)
+ {
+ continue;
+ }
+ input = AddColorInformation(input, input[^name.Length..], statement.Color, statement.SearchMode);
}
-
- matches = Regex.Matches(input, @"^!<[a-zA-Z0-9]+");
- for (int i = 0; i < matches.Count; i++)
+ if (statement.SearchMode == SearchMode.Exact && input.Equals(name))
{
- input = AddColorInformation(input, matches[i].Value, ConsoleColor.Blue, SearchMode.StartOfLine);
+ if (statement.Seperator is not null && input.Contains(statement.Seperator))
+ {
+ input = AddColorInformation(input, statement.Seperator, statement.Color, SearchMode.StartOfLine);
+ }
+ else if (statement.Seperator is not null)
+ {
+ continue;
+ }
+ input = AddColorInformation(input, input, statement.Color, statement.SearchMode);
}
}
- foreach (string part in input.Split("\0"))
+ matches = VariableRegex().Matches(input);
+ for (int i = 0; i < matches.Count; i++)
{
- ConsoleColor consoleColor;
- string messagePart = part;
+ input = AddColorInformation(input, matches[i].Value, ConsoleColor.Cyan, SearchMode.Contains);
+ }
- string stringColor = Regex.Match(messagePart, "(?<=(\\r))(.*)(?=\\r)").Value;
- bool succ = int.TryParse(stringColor, out int colorIndex);
- if (succ && colorIndex >= 0 && colorIndex < 16)
- {
- messagePart = messagePart.Replace($"\r{stringColor}\r", string.Empty);
- consoleColor = (ConsoleColor)colorIndex;
- }
- else
- {
- consoleColor = ConsoleColor.White;
- }
+ matches = VariableDeclarationRegex().Matches(input);
+ for (int i = 0; i < matches.Count; i++)
+ {
+ input = AddColorInformation(input, matches[i].Value, ConsoleColor.DarkCyan, SearchMode.StartOfLine);
+ }
- if (consoleColor == Console.BackgroundColor)
- {
- consoleColor = ConsoleColor.White;
- }
- Console.ForegroundColor = consoleColor;
- Console.Write(messagePart);
+ matches = GlobalVariableDeclarationRegex().Matches(input);
+ for (int i = 0; i < matches.Count; i++)
+ {
+ input = AddColorInformation(input, matches[i].Value, ConsoleColor.Blue, SearchMode.StartOfLine);
}
- Console.ForegroundColor = ConsoleColor.Gray;
}
- private static string AddColorInformation(string originalString, string value, ConsoleColor color, SearchMode searchMode)
+ foreach (string part in input.Split("\0"))
{
- int spacesAtEnd = value.WhiteSpaceAtEnd();
- string reult = searchMode switch
+ ConsoleColor consoleColor;
+ string messagePart = part;
+
+ string stringColor = StringColorRegex().Match(messagePart).Value;
+ bool succ = int.TryParse(stringColor, out int colorIndex);
+ if (succ && colorIndex >= 0 && colorIndex < 16)
{
- SearchMode.StartOfLine => originalString.ReplaceFirstOccurrence(value, $"\0\r{(int)color}\r{value.TrimEnd()}\0" + new string(' ', spacesAtEnd)),
- SearchMode.EndOfLine => originalString.ReplaceLastOccurrence(value, $"\0\r{(int)color}\r{value.TrimEnd()}\0" + new string(' ', spacesAtEnd)),
- _ => originalString.Replace(value, $"\0\r{(int)color}\r{value.TrimEnd()}\0" + new string(' ', spacesAtEnd))
- };
- return reult;
+ messagePart = messagePart.Replace($"\r{stringColor}\r", string.Empty);
+ consoleColor = (ConsoleColor)colorIndex;
+ }
+ else
+ {
+ consoleColor = ConsoleColor.White;
+ }
+
+ if (consoleColor == Console.BackgroundColor)
+ {
+ consoleColor = ConsoleColor.White;
+ }
+ Console.ForegroundColor = consoleColor;
+ Console.Write(messagePart);
}
+ Console.ForegroundColor = ConsoleColor.Gray;
}
+
+ private static string AddColorInformation(string originalString, string value, ConsoleColor color, SearchMode searchMode)
+ {
+ int spacesAtEnd = value.WhiteSpaceAtEnd();
+ string reult = searchMode switch
+ {
+ SearchMode.StartOfLine => originalString.ReplaceFirstOccurrence(value, $"\0\r{(int)color}\r{value.TrimEnd()}\0" + new string(' ', spacesAtEnd)),
+ SearchMode.EndOfLine => originalString.ReplaceLastOccurrence(value, $"\0\r{(int)color}\r{value.TrimEnd()}\0" + new string(' ', spacesAtEnd)),
+ _ => originalString.Replace(value, $"\0\r{(int)color}\r{value.TrimEnd()}\0" + new string(' ', spacesAtEnd))
+ };
+ return reult;
+ }
+
+ [GeneratedRegex("!!.")]
+ private static partial Regex EscapeSequenceRegex();
+
+ [GeneratedRegex("^<[a-zA-Z0-9]+")]
+ private static partial Regex VariableDeclarationRegex();
+
+ [GeneratedRegex("^!<[a-zA-Z0-9]+")]
+ private static partial Regex GlobalVariableDeclarationRegex();
+
+ [GeneratedRegex(">[a-zA-Z0-9]+")]
+ private static partial Regex VariableRegex();
+
+ [GeneratedRegex("(?<=(\\r))(.*)(?=\\r)")]
+ private static partial Regex StringColorRegex();
}
\ No newline at end of file
diff --git a/YesNt.CodeEditor/YesNt.CodeEditor.csproj b/YesNt.CodeEditor/YesNt.CodeEditor.csproj
index 16be40b..dd3b5de 100644
--- a/YesNt.CodeEditor/YesNt.CodeEditor.csproj
+++ b/YesNt.CodeEditor/YesNt.CodeEditor.csproj
@@ -2,7 +2,7 @@
Exe
- net5.0
+ net7.0
AnyCPU;x64
diff --git a/YesNt.Interpreter.Tests/YesNt.Interpreter.Tests.csproj b/YesNt.Interpreter.Tests/YesNt.Interpreter.Tests.csproj
index 9e6dacd..5172e5e 100644
--- a/YesNt.Interpreter.Tests/YesNt.Interpreter.Tests.csproj
+++ b/YesNt.Interpreter.Tests/YesNt.Interpreter.Tests.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net7.0
enable
false
diff --git a/YesNt.Interpreter/Statements/ProcessingStatements.cs b/YesNt.Interpreter/Statements/ProcessingStatements.cs
index 5efe797..2d80026 100644
--- a/YesNt.Interpreter/Statements/ProcessingStatements.cs
+++ b/YesNt.Interpreter/Statements/ProcessingStatements.cs
@@ -9,112 +9,112 @@ using YesNt.Interpreter.Enums;
using YesNt.Interpreter.Runtime;
using YesNt.Interpreter.Utilities;
-namespace YesNt.Interpreter.Statements
+namespace YesNt.Interpreter.Statements;
+
+internal partial class ProcessingStatements : StatementRuntimeInformation
{
- internal class ProcessingStatements : StatementRuntimeInformation
+ [Statement("!calc", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.High)]
+ public void Calculate(string args)
{
- private static readonly Regex calculationRegex = new Regex(@"[0-9*+().,^%/-]+[0-9*+ ().,^%/-]+[0-9*+().,^%/-]+");
+ MatchCollection matches = CalculationRegex().Matches(args.FromSaveString());
- [Statement("!calc", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.High)]
- public void Calculate(string args)
+ for (int i = 0; i < matches.Count; i++)
{
- MatchCollection matches = calculationRegex.Matches(args.FromSaveString());
-
- for (int i = 0; i < matches.Count; i++)
+ string res = Evaluator.Calculate(matches[i].Value);
+ if (res is null)
{
- string res = Evaluator.Calculate(matches[i].Value);
- if (res is null)
+ RuntimeInfo.Exit("Invalid operation", true);
+ return;
+ }
+ args = args.FromSaveString().Replace(matches[i].Value, res);
+ }
+
+ RuntimeInfo.CurrentLine = args;
+ }
+
+ [Statement("!eval", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.VeryHigh)]
+ public void Evaluate(string args)
+ {
+ RuntimeInfo.CurrentLine = args.FromSaveString();
+ }
+
+ [Statement("!!", SearchMode.Contains, SpaceAround.None, ConsoleColor.DarkYellow, Priority = Priority.PreProcessing, KeepStatementInArgs = true)]
+ public void DontEvaluate(string args)
+ {
+ int index;
+ while ((index = args.IndexOf("!!")) != -1)
+ {
+ args = args.Remove(index, 2);
+ if (index < args.Length)
+ {
+ char charToEscape = args[index];
+ args = args.Remove(index, 1);
+ args = args.Insert(index, charToEscape.ToString().ToSaveString());
+ }
+ }
+ RuntimeInfo.CurrentLine = args;
+ }
+
+ [Statement("!task", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.VeryHigh)]
+ public void RunTask(string line)
+ {
+ int lineNumer = RuntimeInfo.LineNumber;
+ List lines = RuntimeInfo.Lines.GetRange(0, RuntimeInfo.Lines.Count);
+
+ Line oldLine = lines[lineNumer];
+
+ lines[lineNumer] = new Line(line, oldLine.FileName, oldLine.LineNumber);
+ _ = Task.Run(() =>
+ {
+ YesNtInterpreter interpreter = new YesNtInterpreter();
+ interpreter.Initialize();
+ interpreter.Execute(lines, RuntimeInfo.GloablVariables, lineNumer, RuntimeInfo);
+ });
+
+ RuntimeInfo.CurrentLine = string.Empty;
+ }
+
+ [Statement("slp", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
+ public void Sleep(string args)
+ {
+ _ = int.TryParse(args, out int millisecondsTimeout);
+ ConsoleExtentions.Sleep(millisecondsTimeout, RuntimeInfo);
+ }
+
+ [Statement("imp", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
+ public void Import(string path)
+ {
+ path = Path.Combine(RuntimeInfo.WorkingDirectory, path);
+
+ if (string.IsNullOrEmpty(Path.GetExtension(path)))
+ {
+ path = Path.ChangeExtension(path, "ynt");
+ }
+
+ if (File.Exists(path))
+ {
+ try
+ {
+ RuntimeInfo.Lines.RemoveAt(RuntimeInfo.LineNumber);
+ string[] lines = File.ReadAllLines(path);
+
+ for (int i = 0; i < lines.Length; i++)
{
- RuntimeInfo.Exit("Invalid operation", true);
- return;
+ RuntimeInfo.Lines.Insert(RuntimeInfo.LineNumber + i, new Line(lines[i], Path.GetFileName(path), i));
}
- args = args.FromSaveString().Replace(matches[i].Value, res);
+ RuntimeInfo.LineNumber--;
}
-
- RuntimeInfo.CurrentLine = args;
- }
-
- [Statement("!eval", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.VeryHigh)]
- public void Evaluate(string args)
- {
- RuntimeInfo.CurrentLine = args.FromSaveString();
- }
-
- [Statement("!!", SearchMode.Contains, SpaceAround.None, ConsoleColor.DarkYellow, Priority = Priority.PreProcessing, KeepStatementInArgs = true)]
- public void DontEvaluate(string args)
- {
- int index;
- while ((index = args.IndexOf("!!")) != -1)
+ catch
{
- args = args.Remove(index, 2);
- if (index < args.Length)
- {
- char charToEscape = args[index];
- args = args.Remove(index, 1);
- args = args.Insert(index, charToEscape.ToString().ToSaveString());
- }
+ RuntimeInfo.Exit($"Could not load file \"{path}\"", true);
}
- RuntimeInfo.CurrentLine = args;
}
-
- [Statement("!task", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.VeryHigh)]
- public void RunTask(string line)
+ else
{
- int lineNumer = RuntimeInfo.LineNumber;
- List lines = RuntimeInfo.Lines.GetRange(0, RuntimeInfo.Lines.Count);
-
- Line oldLine = lines[lineNumer];
-
- lines[lineNumer] = new Line(line, oldLine.FileName, oldLine.LineNumber);
- _ = Task.Run(() =>
- {
- YesNtInterpreter interpreter = new YesNtInterpreter();
- interpreter.Initialize();
- interpreter.Execute(lines, RuntimeInfo.GloablVariables, lineNumer, RuntimeInfo);
- });
-
- RuntimeInfo.CurrentLine = string.Empty;
- }
-
- [Statement("slp", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
- public void Sleep(string args)
- {
- _ = int.TryParse(args, out int millisecondsTimeout);
- ConsoleExtentions.Sleep(millisecondsTimeout, RuntimeInfo);
- }
-
- [Statement("imp", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
- public void Import(string path)
- {
- path = Path.Combine(RuntimeInfo.WorkingDirectory, path);
-
- if (string.IsNullOrEmpty(Path.GetExtension(path)))
- {
- path = Path.ChangeExtension(path, "ynt");
- }
-
- if (File.Exists(path))
- {
- try
- {
- RuntimeInfo.Lines.RemoveAt(RuntimeInfo.LineNumber);
- string[] lines = File.ReadAllLines(path);
-
- for (int i = 0; i < lines.Length; i++)
- {
- RuntimeInfo.Lines.Insert(RuntimeInfo.LineNumber + i, new Line(lines[i], Path.GetFileName(path), i));
- }
- RuntimeInfo.LineNumber--;
- }
- catch
- {
- RuntimeInfo.Exit($"Could not load file \"{path}\"", true);
- }
- }
- else
- {
- RuntimeInfo.Exit($"Could not find file \"{path}\"", true);
- }
+ RuntimeInfo.Exit($"Could not find file \"{path}\"", true);
}
}
+
+ [GeneratedRegex("[0-9*+().,^%/-]+[0-9*+ ().,^%/-]+[0-9*+().,^%/-]+")]
+ private static partial Regex CalculationRegex();
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Statements/VariableStatements.cs b/YesNt.Interpreter/Statements/VariableStatements.cs
index 06194a2..98eb57d 100644
--- a/YesNt.Interpreter/Statements/VariableStatements.cs
+++ b/YesNt.Interpreter/Statements/VariableStatements.cs
@@ -5,119 +5,119 @@ using YesNt.Interpreter.Attributes;
using YesNt.Interpreter.Enums;
using YesNt.Interpreter.Runtime;
-namespace YesNt.Interpreter.Statements
+namespace YesNt.Interpreter.Statements;
+
+internal partial class VariableStatements : StatementRuntimeInformation
{
- internal class VariableStatements : StatementRuntimeInformation
+ [Statement("<", SearchMode.StartOfLine, SpaceAround.None, Priority = Priority.VeryLow)]
+ public void DefineVariable(string args)
{
- private static readonly Regex variableStatementRegex = new Regex(@">[a-zA-Z0-9]+");
-
- [Statement("<", SearchMode.StartOfLine, SpaceAround.None, Priority = Priority.VeryLow)]
- public void DefineVariable(string args)
+ string[] parts = args.Split('=');
+ if (parts.Length == 2)
{
- string[] parts = args.Split('=');
- if (parts.Length == 2)
+ string key = parts[0].Trim();
+ if (key.Contains(' '))
{
- string key = parts[0].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());
- }
+ RuntimeInfo.Exit("Invalid Syntax", true);
}
- else
- {
- RuntimeInfo.Exit("Invalid syntax", true);
- }
- }
-
- [Statement("!<", SearchMode.StartOfLine, SpaceAround.None, Priority = Priority.VeryLow)]
- public void DefineGlobalVariable(string args)
- {
- string[] parts = args.Split('=');
- if (parts.Length == 2)
- {
- string key = parts[0].Trim();
- if (key.Contains(' '))
- {
- RuntimeInfo.Exit("Invalid Syntax", true);
- }
-
- if (RuntimeInfo.GloablVariables.ContainsKey(key))
- {
- RuntimeInfo.GloablVariables[key] = parts[1].Trim();
- }
- else
- {
- RuntimeInfo.GloablVariables.Add(key, parts[1].Trim());
- }
- }
- else
- {
- RuntimeInfo.Exit("Invalid syntax", true);
- }
- }
-
- [Statement("del", SearchMode.StartOfLine, SpaceAround.End, System.ConsoleColor.Red, Priority = Priority.VeryLow)]
- public void DeleteVariable(string args)
- {
- string key = args.Trim();
if (RuntimeInfo.Variables.ContainsKey(key))
{
- _ = RuntimeInfo.Variables.Remove(key);
- }
- else if (RuntimeInfo.GloablVariables.ContainsKey(key))
- {
- _ = RuntimeInfo.GloablVariables.Remove(key);
+ RuntimeInfo.Variables[key] = parts[1].Trim();
}
else
{
- RuntimeInfo.Exit($"Variable \"{key}\" not found", true);
+ RuntimeInfo.Variables.Add(key, parts[1].Trim());
}
}
-
- [Statement(">", SearchMode.Contains, SpaceAround.None, Priority = Priority.Highest)]
- public void ReadVariable(string _)
+ else
{
- if (!RuntimeInfo.CurrentLine.Contains('>'))
+ RuntimeInfo.Exit("Invalid syntax", true);
+ }
+ }
+
+ [Statement("!<", SearchMode.StartOfLine, SpaceAround.None, Priority = Priority.VeryLow)]
+ public void DefineGlobalVariable(string args)
+ {
+ string[] parts = args.Split('=');
+ if (parts.Length == 2)
+ {
+ string key = parts[0].Trim();
+ if (key.Contains(' '))
{
+ RuntimeInfo.Exit("Invalid Syntax", true);
+ }
+
+ if (RuntimeInfo.GloablVariables.ContainsKey(key))
+ {
+ RuntimeInfo.GloablVariables[key] = parts[1].Trim();
+ }
+ else
+ {
+ RuntimeInfo.GloablVariables.Add(key, parts[1].Trim());
+ }
+ }
+ else
+ {
+ RuntimeInfo.Exit("Invalid syntax", true);
+ }
+ }
+
+ [Statement("del", SearchMode.StartOfLine, SpaceAround.End, System.ConsoleColor.Red, Priority = Priority.VeryLow)]
+ public void DeleteVariable(string args)
+ {
+ string key = args.Trim();
+
+ if (RuntimeInfo.Variables.ContainsKey(key))
+ {
+ _ = RuntimeInfo.Variables.Remove(key);
+ }
+ else if (RuntimeInfo.GloablVariables.ContainsKey(key))
+ {
+ _ = RuntimeInfo.GloablVariables.Remove(key);
+ }
+ else
+ {
+ RuntimeInfo.Exit($"Variable \"{key}\" not found", true);
+ }
+ }
+
+ [Statement(">", SearchMode.Contains, SpaceAround.None, Priority = Priority.Highest)]
+ public void ReadVariable(string _)
+ {
+ if (!RuntimeInfo.CurrentLine.Contains('>'))
+ {
+ return;
+ }
+
+ foreach (KeyValuePair variable in RuntimeInfo.Variables)
+ {
+ RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{variable.Key}", variable.Value);
+ }
+
+ foreach (KeyValuePair variable in RuntimeInfo.GloablVariables)
+ {
+ RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{variable.Key}", variable.Value);
+ }
+
+ if (RuntimeInfo.IsSearching)
+ {
+ return;
+ }
+
+ MatchCollection matches = VariableStatementRegex().Matches(RuntimeInfo.CurrentLine);
+
+ for (int i = 0; i < matches.Count; i++)
+ {
+ string varName = matches[i].Value.Replace(">", string.Empty);
+ if (!RuntimeInfo.Variables.ContainsKey(varName) && !RuntimeInfo.GloablVariables.ContainsKey(varName))
+ {
+ RuntimeInfo.Exit($"Variable \"{varName}\" not found", true);
return;
}
-
- foreach (KeyValuePair variable in RuntimeInfo.Variables)
- {
- RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{variable.Key}", variable.Value);
- }
-
- foreach (KeyValuePair variable in RuntimeInfo.GloablVariables)
- {
- RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{variable.Key}", variable.Value);
- }
-
- if (RuntimeInfo.IsSearching)
- {
- return;
- }
-
- MatchCollection matches = variableStatementRegex.Matches(RuntimeInfo.CurrentLine);
-
- for (int i = 0; i < matches.Count; i++)
- {
- string varName = matches[i].Value.Replace(">", string.Empty);
- if (!RuntimeInfo.Variables.ContainsKey(varName) && !RuntimeInfo.GloablVariables.ContainsKey(varName))
- {
- RuntimeInfo.Exit($"Variable \"{varName}\" not found", true);
- return;
- }
- }
}
}
+
+ [GeneratedRegex(">[a-zA-Z0-9]+")]
+ private static partial Regex VariableStatementRegex();
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Utilities/Evaluator.cs b/YesNt.Interpreter/Utilities/Evaluator.cs
index aac7d50..ecd39ff 100644
--- a/YesNt.Interpreter/Utilities/Evaluator.cs
+++ b/YesNt.Interpreter/Utilities/Evaluator.cs
@@ -2,177 +2,191 @@
using System.Linq;
using System.Text.RegularExpressions;
-namespace YesNt.Interpreter.Utilities
+namespace YesNt.Interpreter.Utilities;
+
+internal static partial class Evaluator
{
- internal static class Evaluator
+ public static bool? EvaluateCondition(string input)
{
- public static bool? EvaluateCondition(string input)
+ if (input.ToLower().FromSaveString().Trim() == "true")
{
- if (input.ToLower().FromSaveString().Trim() == "true")
- {
- return true;
- }
- else if (input.ToLower().FromSaveString().Trim() == "false")
- {
- return false;
- }
+ return true;
+ }
+ else if (input.ToLower().FromSaveString().Trim() == "false")
+ {
+ return false;
+ }
- string[] parts = input.Split("==");
- if (parts.Length == 2)
- {
- string part1 = parts[0].FromSaveString().Trim();
- string part2 = parts[1].FromSaveString().Trim();
- return part1 == part2;
- }
+ string[] parts = input.Split("==");
+ if (parts.Length == 2)
+ {
+ string part1 = parts[0].FromSaveString().Trim();
+ string part2 = parts[1].FromSaveString().Trim();
+ return part1 == part2;
+ }
- parts = input.Split("!=");
- if (parts.Length == 2)
- {
- string part1 = parts[0].FromSaveString().Trim();
- string part2 = parts[1].FromSaveString().Trim();
- return part1 != part2;
- }
+ parts = input.Split("!=");
+ if (parts.Length == 2)
+ {
+ string part1 = parts[0].FromSaveString().Trim();
+ string part2 = parts[1].FromSaveString().Trim();
+ return part1 != part2;
+ }
- parts = input.Split(">=");
- if (parts.Length == 2)
- {
- bool succ1 = parts[0].ToStandardizedNumber(out double part1);
- bool succ2 = parts[1].ToStandardizedNumber(out double part2);
- return succ1 && succ2 && part1 >= part2;
- }
+ parts = input.Split(">=");
+ if (parts.Length == 2)
+ {
+ bool succ1 = parts[0].ToStandardizedNumber(out double part1);
+ bool succ2 = parts[1].ToStandardizedNumber(out double part2);
+ return succ1 && succ2 && part1 >= part2;
+ }
- parts = input.Split("<=");
- if (parts.Length == 2)
- {
- bool succ1 = parts[0].ToStandardizedNumber(out double part1);
- bool succ2 = parts[1].ToStandardizedNumber(out double part2);
- return succ1 && succ2 && part1 <= part2;
- }
+ parts = input.Split("<=");
+ if (parts.Length == 2)
+ {
+ bool succ1 = parts[0].ToStandardizedNumber(out double part1);
+ bool succ2 = parts[1].ToStandardizedNumber(out double part2);
+ return succ1 && succ2 && part1 <= part2;
+ }
- parts = input.Split(">");
- if (parts.Length == 2)
- {
- bool succ1 = parts[0].ToStandardizedNumber(out double part1);
- bool succ2 = parts[1].ToStandardizedNumber(out double part2);
- return succ1 && succ2 && part1 > part2;
- }
+ parts = input.Split(">");
+ if (parts.Length == 2)
+ {
+ bool succ1 = parts[0].ToStandardizedNumber(out double part1);
+ bool succ2 = parts[1].ToStandardizedNumber(out double part2);
+ return succ1 && succ2 && part1 > part2;
+ }
- parts = input.Split("<");
- if (parts.Length == 2)
- {
- bool succ1 = parts[0].ToStandardizedNumber(out double part1);
- bool succ2 = parts[1].ToStandardizedNumber(out double part2);
- return succ1 && succ2 && part1 < part2;
- }
+ parts = input.Split("<");
+ if (parts.Length == 2)
+ {
+ bool succ1 = parts[0].ToStandardizedNumber(out double part1);
+ bool succ2 = parts[1].ToStandardizedNumber(out double part2);
+ return succ1 && succ2 && part1 < part2;
+ }
+ return null;
+ }
+
+ public static string Calculate(string input)
+ {
+ input = PlusPlusRegex().Replace(input, "+");
+ input = MinusMinusRegex().Replace(input, "+");
+ input = MinusPlusRegex().Replace(input, "-");
+ input = PlusMinusRegex().Replace(input, "-");
+
+ string yes = Calculate(input, '+');
+ return yes;
+ }
+
+ private static string Calculate(string input, char op)
+ {
+ if (input is null)
+ {
return null;
}
- public static string Calculate(string input)
- {
- input = Regex.Replace(input, @"(\+ +\+)+", "+");
- input = Regex.Replace(input, @"(\- +\-)+", "+");
- input = Regex.Replace(input, @"(\- +\+)+", "-");
- input = Regex.Replace(input, @"(\+ +\-)+", "-");
+ input = input.FromSaveString();
- string yes = Calculate(input, '+');
- return yes;
+ MatchCollection matches = ParenthesesRegex().Matches(input);
+ while (matches.Count > 0)
+ {
+ for (int i = 0; i < matches.Count; i++)
+ {
+ string calc = matches[i].Value.Substring(1, matches[i].Length - 2);
+ string ret = Calculate(calc);
+ input = input.Replace(matches[i].Value, ret);
+ }
+ matches = ParenthesesRegex().Matches(input);
}
- private static string Calculate(string input, char op)
+ string[] parts = input.Split(op);
+
+ //Weird fix
+ if (parts.Length >= 2 && string.IsNullOrWhiteSpace(parts[0]))
{
- if (input is null)
+ parts[1] = $"{op}{parts[1]}";
+ parts = parts.Skip(1).ToArray();
+ }
+
+ double number = double.NaN;
+
+ foreach (string p in parts)
+ {
+ string part = p;
+
+ part = op switch
+ {
+ '+' => Calculate(part, '-'),
+ '-' => Calculate(part, '*'),
+ '*' => Calculate(part, '/'),
+ '/' => Calculate(part, '%'),
+ '%' => Calculate(part, '^'),
+ _ => part
+ };
+
+ if (part is null)
{
return null;
}
- input = input.FromSaveString();
-
- MatchCollection matches = Regex.Matches(input, @"\(([^()]+)\)");
- while (matches.Count > 0)
+ if (part.ToStandardizedNumber(out double num))
{
- for (int i = 0; i < matches.Count; i++)
+ if (double.IsNaN(number))
{
- string calc = matches[i].Value.Substring(1, matches[i].Length - 2);
- string ret = Calculate(calc);
- input = input.Replace(matches[i].Value, ret);
- }
- matches = Regex.Matches(input, @"\(([^()]+)\)");
- }
-
- string[] parts = input.Split(op);
-
- //Weird fix
- if (parts.Length >= 2 && string.IsNullOrWhiteSpace(parts[0]))
- {
- parts[1] = $"{op}{parts[1]}";
- parts = parts.Skip(1).ToArray();
- }
-
- double number = double.NaN;
-
- foreach (string p in parts)
- {
- string part = p;
-
- part = op switch
- {
- '+' => Calculate(part, '-'),
- '-' => Calculate(part, '*'),
- '*' => Calculate(part, '/'),
- '/' => Calculate(part, '%'),
- '%' => Calculate(part, '^'),
- _ => part
- };
-
- if (part is null)
- {
- return null;
- }
-
- if (part.ToStandardizedNumber(out double num))
- {
- if (double.IsNaN(number))
- {
- number = num;
- }
- else
- {
- switch (op)
- {
- case '+':
- number += num;
- break;
-
- case '-':
- number -= num;
- break;
-
- case '*':
- number *= num;
- break;
-
- case '/':
- number /= num;
- break;
-
- case '%':
- number %= num;
- break;
-
- case '^':
- number = Math.Pow(number, num);
- break;
- }
- }
+ number = num;
}
else
{
- return null;
+ switch (op)
+ {
+ case '+':
+ number += num;
+ break;
+
+ case '-':
+ number -= num;
+ break;
+
+ case '*':
+ number *= num;
+ break;
+
+ case '/':
+ number /= num;
+ break;
+
+ case '%':
+ number %= num;
+ break;
+
+ case '^':
+ number = Math.Pow(number, num);
+ break;
+ }
}
}
-
- return number.ToString(System.Globalization.CultureInfo.InvariantCulture);
+ else
+ {
+ return null;
+ }
}
+
+ return number.ToString(System.Globalization.CultureInfo.InvariantCulture);
}
+
+ [GeneratedRegex("\\(([^()]+)\\)")]
+ private static partial Regex ParenthesesRegex();
+
+ [GeneratedRegex("(\\+ +\\+)+")]
+ private static partial Regex PlusPlusRegex();
+
+ [GeneratedRegex("(\\- +\\-)+")]
+ private static partial Regex MinusMinusRegex();
+
+ [GeneratedRegex("(\\- +\\+)+")]
+ private static partial Regex MinusPlusRegex();
+
+ [GeneratedRegex("(\\+ +\\-)+")]
+ private static partial Regex PlusMinusRegex();
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Utilities/FixedProcess.cs b/YesNt.Interpreter/Utilities/FixedProcess.cs
index 9ee542d..46ee530 100644
--- a/YesNt.Interpreter/Utilities/FixedProcess.cs
+++ b/YesNt.Interpreter/Utilities/FixedProcess.cs
@@ -23,14 +23,14 @@ namespace YesNt.Interpreter.Utilities
public new void BeginOutputReadLine()
{
Stream baseStream = StandardOutput.BaseStream;
- output = new AsyncStreamReader(this, baseStream, new UserCallBack(FixedOutputReadNotifyUser), StandardOutput.CurrentEncoding);
+ output = new AsyncStreamReader(baseStream, new UserCallBack(FixedOutputReadNotifyUser), StandardOutput.CurrentEncoding);
output.BeginReadLine();
}
public new void BeginErrorReadLine()
{
Stream baseStream = StandardError.BaseStream;
- error = new AsyncStreamReader(this, baseStream, new UserCallBack(FixedErrorReadNotifyUser), StandardError.CurrentEncoding);
+ error = new AsyncStreamReader(baseStream, new UserCallBack(FixedErrorReadNotifyUser), StandardError.CurrentEncoding);
error.BeginReadLine();
}
@@ -90,17 +90,17 @@ namespace YesNt.Interpreter.Utilities
public virtual Encoding CurrentEncoding => encoding;
public virtual Stream BaseStream => stream;
- internal AsyncStreamReader(Process process, Stream stream, UserCallBack callback, Encoding encoding) : this(process, stream, callback, encoding, 1024)
+ internal AsyncStreamReader(Stream stream, UserCallBack callback, Encoding encoding) : this(stream, callback, encoding, 1024)
{
}
- internal AsyncStreamReader(Process process, Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
+ internal AsyncStreamReader(Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
{
- Init(process, stream, callback, encoding, bufferSize);
+ Init(stream, callback, encoding, bufferSize);
messageQueue = new Queue();
}
- private void Init(Process process, Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
+ private void Init(Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
{
this.stream = stream;
this.encoding = encoding;
diff --git a/YesNt.Interpreter/YesNt.Interpreter.csproj b/YesNt.Interpreter/YesNt.Interpreter.csproj
index bd4ef12..3b71ea2 100644
--- a/YesNt.Interpreter/YesNt.Interpreter.csproj
+++ b/YesNt.Interpreter/YesNt.Interpreter.csproj
@@ -1,7 +1,7 @@
- net5.0
+ net7.0
YesNt.Interpreter
Exe
From 9d22381085a585382634be7c041929ba18dd16a7 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Thu, 17 Nov 2022 12:58:05 +0100
Subject: [PATCH 07/73] Rename SaveString to SafeString
---
.../Runtime/RuntimeInformation.cs | 12 +--
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 4 +-
.../Statements/ConsoleStatements.cs | 4 +-
.../Statements/ProcessingStatements.cs | 8 +-
.../Statements/SystemStatements.cs | 2 +-
YesNt.Interpreter/Utilities/Evaluator.cs | 14 ++--
.../Utilities/StringExtentions.cs | 83 +++++++++----------
7 files changed, 63 insertions(+), 64 deletions(-)
diff --git a/YesNt.Interpreter/Runtime/RuntimeInformation.cs b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
index 8113c6b..2e70a69 100644
--- a/YesNt.Interpreter/Runtime/RuntimeInformation.cs
+++ b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
@@ -81,16 +81,16 @@ namespace YesNt.Interpreter.Runtime
{
if (IsTask)
{
- parentRuntimeInformation!.WriteLine(output.FromSaveString(), forceWrite);
+ parentRuntimeInformation!.WriteLine(output.FromSafeString(), forceWrite);
}
else
{
- OnDebugOutput?.Invoke(output.FromSaveString() + Environment.NewLine);
+ OnDebugOutput?.Invoke(output.FromSafeString() + Environment.NewLine);
}
}
else
{
- Console.WriteLine(output.FromSaveString());
+ Console.WriteLine(output.FromSafeString());
}
}
@@ -105,16 +105,16 @@ namespace YesNt.Interpreter.Runtime
{
if (IsTask)
{
- parentRuntimeInformation!.Write(output.FromSaveString(), forceWrite);
+ parentRuntimeInformation!.Write(output.FromSafeString(), forceWrite);
}
else
{
- OnDebugOutput?.Invoke(output.FromSaveString());
+ OnDebugOutput?.Invoke(output.FromSafeString());
}
}
else
{
- Console.Write(output.FromSaveString());
+ Console.Write(output.FromSafeString());
}
}
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index 7445996..67940ae 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -148,7 +148,7 @@ namespace YesNt.Interpreter.Runtime
DebugEventArgs debugEventArgs = new DebugEventArgs()
{
LineNumber = runtimeInfo.LineNumber + 1,
- OriginalLine = runtimeInfo.CurrentLine.FromSaveString(),
+ OriginalLine = runtimeInfo.CurrentLine.FromSafeString(),
IsTask = runtimeInfo.IsTask,
TaskId = runtimeInfo.TaskId
};
@@ -229,7 +229,7 @@ namespace YesNt.Interpreter.Runtime
}
if (runtimeInfo.IsDebugMode && notSearchingLabel)
{
- debugEventArgs.CurrentLine = runtimeInfo.CurrentLine.FromSaveString();
+ debugEventArgs.CurrentLine = runtimeInfo.CurrentLine.FromSafeString();
runtimeInfo.LineExecuted(debugEventArgs);
}
}
diff --git a/YesNt.Interpreter/Statements/ConsoleStatements.cs b/YesNt.Interpreter/Statements/ConsoleStatements.cs
index 1d07072..574df89 100644
--- a/YesNt.Interpreter/Statements/ConsoleStatements.cs
+++ b/YesNt.Interpreter/Statements/ConsoleStatements.cs
@@ -34,7 +34,7 @@ namespace YesNt.Interpreter.Statements
RuntimeInfo.Exit("Terminated by external process", true);
return;
}
- args = args.ReplaceFirstOccurrence("%crl ", input.ToSaveString() + " ");
+ args = args.ReplaceFirstOccurrence("%crl ", input.ToSafeString() + " ");
}
RuntimeInfo.CurrentLine = args.TrimEnd();
}
@@ -46,7 +46,7 @@ namespace YesNt.Interpreter.Statements
while (args.Contains("%cr "))
{
string input = ConsoleExtentions.ReadKey(RuntimeInfo).ToString();
- args = args.ReplaceFirstOccurrence("%cr ", input.ToSaveString() + " ");
+ args = args.ReplaceFirstOccurrence("%cr ", input.ToSafeString() + " ");
}
RuntimeInfo.CurrentLine = args.TrimEnd();
}
diff --git a/YesNt.Interpreter/Statements/ProcessingStatements.cs b/YesNt.Interpreter/Statements/ProcessingStatements.cs
index 2d80026..8c77aa8 100644
--- a/YesNt.Interpreter/Statements/ProcessingStatements.cs
+++ b/YesNt.Interpreter/Statements/ProcessingStatements.cs
@@ -16,7 +16,7 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
[Statement("!calc", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.High)]
public void Calculate(string args)
{
- MatchCollection matches = CalculationRegex().Matches(args.FromSaveString());
+ MatchCollection matches = CalculationRegex().Matches(args.FromSafeString());
for (int i = 0; i < matches.Count; i++)
{
@@ -26,7 +26,7 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
RuntimeInfo.Exit("Invalid operation", true);
return;
}
- args = args.FromSaveString().Replace(matches[i].Value, res);
+ args = args.FromSafeString().Replace(matches[i].Value, res);
}
RuntimeInfo.CurrentLine = args;
@@ -35,7 +35,7 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
[Statement("!eval", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.VeryHigh)]
public void Evaluate(string args)
{
- RuntimeInfo.CurrentLine = args.FromSaveString();
+ RuntimeInfo.CurrentLine = args.FromSafeString();
}
[Statement("!!", SearchMode.Contains, SpaceAround.None, ConsoleColor.DarkYellow, Priority = Priority.PreProcessing, KeepStatementInArgs = true)]
@@ -49,7 +49,7 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
{
char charToEscape = args[index];
args = args.Remove(index, 1);
- args = args.Insert(index, charToEscape.ToString().ToSaveString());
+ args = args.Insert(index, charToEscape.ToString().ToSafeString());
}
}
RuntimeInfo.CurrentLine = args;
diff --git a/YesNt.Interpreter/Statements/SystemStatements.cs b/YesNt.Interpreter/Statements/SystemStatements.cs
index ac357b7..d1a3ee4 100644
--- a/YesNt.Interpreter/Statements/SystemStatements.cs
+++ b/YesNt.Interpreter/Statements/SystemStatements.cs
@@ -16,7 +16,7 @@ namespace YesNt.Interpreter.Statements
[Statement("exc", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta, Priority = Priority.Low, Seperator = "|")]
public void ExecuteProgramWithArgs(string input)
{
- string[] parts = input.FromSaveString().Split('|');
+ string[] parts = input.FromSafeString().Split('|');
parts[0] = parts[0].Trim();
string[] functionArgumets = parts[1].Split(',');
diff --git a/YesNt.Interpreter/Utilities/Evaluator.cs b/YesNt.Interpreter/Utilities/Evaluator.cs
index ecd39ff..a13fa91 100644
--- a/YesNt.Interpreter/Utilities/Evaluator.cs
+++ b/YesNt.Interpreter/Utilities/Evaluator.cs
@@ -8,11 +8,11 @@ internal static partial class Evaluator
{
public static bool? EvaluateCondition(string input)
{
- if (input.ToLower().FromSaveString().Trim() == "true")
+ if (input.ToLower().FromSafeString().Trim() == "true")
{
return true;
}
- else if (input.ToLower().FromSaveString().Trim() == "false")
+ else if (input.ToLower().FromSafeString().Trim() == "false")
{
return false;
}
@@ -20,16 +20,16 @@ internal static partial class Evaluator
string[] parts = input.Split("==");
if (parts.Length == 2)
{
- string part1 = parts[0].FromSaveString().Trim();
- string part2 = parts[1].FromSaveString().Trim();
+ string part1 = parts[0].FromSafeString().Trim();
+ string part2 = parts[1].FromSafeString().Trim();
return part1 == part2;
}
parts = input.Split("!=");
if (parts.Length == 2)
{
- string part1 = parts[0].FromSaveString().Trim();
- string part2 = parts[1].FromSaveString().Trim();
+ string part1 = parts[0].FromSafeString().Trim();
+ string part2 = parts[1].FromSafeString().Trim();
return part1 != part2;
}
@@ -86,7 +86,7 @@ internal static partial class Evaluator
return null;
}
- input = input.FromSaveString();
+ input = input.FromSafeString();
MatchCollection matches = ParenthesesRegex().Matches(input);
while (matches.Count > 0)
diff --git a/YesNt.Interpreter/Utilities/StringExtentions.cs b/YesNt.Interpreter/Utilities/StringExtentions.cs
index c8e615e..c7a674a 100644
--- a/YesNt.Interpreter/Utilities/StringExtentions.cs
+++ b/YesNt.Interpreter/Utilities/StringExtentions.cs
@@ -2,52 +2,51 @@
using System.Globalization;
using System.Text;
-namespace YesNt.Interpreter.Utilities
+namespace YesNt.Interpreter.Utilities;
+
+public static class StringExtentions
{
- public static class StringExtentions
+ public static string ToSafeString(this string input)
{
- public static string ToSaveString(this string input)
+ StringBuilder output = new StringBuilder();
+ foreach (char c in input)
{
- StringBuilder output = new StringBuilder();
- foreach (char c in input)
- {
- _ = output.Append($"\v{c}\v");
- }
- return output.ToString();
+ _ = output.Append($"\v{c}\v");
+ }
+ return output.ToString();
+ }
+
+ public static string FromSafeString(this string input)
+ {
+ return input.Replace("\v", "");
+ }
+
+ public static bool ToStandardizedNumber(this string input, out double result)
+ {
+ return double.TryParse(input.FromSafeString().Replace(',', '.'), NumberStyles.Any, CultureInfo.InvariantCulture, out result);
+ }
+
+ public static string ReplaceFirstOccurrence(this string input, string oldValue, string newValue)
+ {
+ int place = input.IndexOf(oldValue);
+ return input.Remove(place, oldValue.Length).Insert(place, newValue);
+ }
+
+ public static string ReplaceLastOccurrence(this string input, string oldValue, string newValue)
+ {
+ int place = input.LastIndexOf(oldValue);
+ return input.Remove(place, Math.Min(oldValue.Length, input.Length - place)).Insert(place, newValue);
+ }
+
+ public static int WhiteSpaceAtEnd(this string input)
+ {
+ int count = 0;
+ int index = input.Length - 1;
+ while (index >= 0 && char.IsWhiteSpace(input[index--]))
+ {
+ count++;
}
- public static string FromSaveString(this string input)
- {
- return input.Replace("\v", "");
- }
-
- public static bool ToStandardizedNumber(this string input, out double result)
- {
- return double.TryParse(input.FromSaveString().Replace(',', '.'), NumberStyles.Any, CultureInfo.InvariantCulture, out result);
- }
-
- public static string ReplaceFirstOccurrence(this string input, string oldValue, string newValue)
- {
- int place = input.IndexOf(oldValue);
- return input.Remove(place, oldValue.Length).Insert(place, newValue);
- }
-
- public static string ReplaceLastOccurrence(this string input, string oldValue, string newValue)
- {
- int place = input.LastIndexOf(oldValue);
- return input.Remove(place, Math.Min(oldValue.Length, input.Length - place)).Insert(place, newValue);
- }
-
- public static int WhiteSpaceAtEnd(this string input)
- {
- int count = 0;
- int index = input.Length - 1;
- while (index >= 0 && char.IsWhiteSpace(input[index--]))
- {
- count++;
- }
-
- return count;
- }
+ return count;
}
}
\ No newline at end of file
From ef1f731adc886f3eb0bb3f00f8eef9b2138da374 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Thu, 17 Nov 2022 14:07:11 +0100
Subject: [PATCH 08/73] Fix exc command
---
YesNt.Interpreter/Statements/SystemStatements.cs | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/YesNt.Interpreter/Statements/SystemStatements.cs b/YesNt.Interpreter/Statements/SystemStatements.cs
index d1a3ee4..cdf66ec 100644
--- a/YesNt.Interpreter/Statements/SystemStatements.cs
+++ b/YesNt.Interpreter/Statements/SystemStatements.cs
@@ -62,6 +62,8 @@ namespace YesNt.Interpreter.Statements
private void StartProcess(string name, string args)
{
+ RuntimeInfo.OutParametersStack.Clear();
+
FixedProcess process = new FixedProcess
{
StartInfo = new ProcessStartInfo()
@@ -82,7 +84,7 @@ namespace YesNt.Interpreter.Statements
process.WaitForExit();
RuntimeInfo.InParametersStack.Clear();
- RuntimeInfo.OutParametersStack.Clear();
+
RuntimeInfo.OutParametersStack.Push(process.ExitCode.ToString());
}
From 2e023f1a4ece5f32bbdfc0d644724abde7a37f26 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Thu, 17 Nov 2022 14:07:29 +0100
Subject: [PATCH 09/73] Add empty cwl command
---
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 425 +++++++++---------
.../Statements/ConsoleStatements.cs | 83 ++--
2 files changed, 256 insertions(+), 252 deletions(-)
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index 67940ae..81974a0 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -9,279 +9,278 @@ using YesNt.Interpreter.Attributes;
using YesNt.Interpreter.Enums;
using YesNt.Interpreter.Utilities;
-namespace YesNt.Interpreter.Runtime
+namespace YesNt.Interpreter.Runtime;
+
+public class YesNtInterpreter
{
- public class YesNtInterpreter
+ private readonly RuntimeInformation runtimeInfo = new RuntimeInformation();
+ private Dictionary> statements = new();
+ private List> staticStatements = new();
+
+ public ReadOnlyCollection StatementInformation
{
- private readonly RuntimeInformation runtimeInfo = new RuntimeInformation();
- private Dictionary> statements = new();
- private List> staticStatements = new();
-
- public ReadOnlyCollection StatementInformation
+ get
{
- get
+ List informations = statements.Select(s =>
{
- List informations = statements.Select(s =>
+ return new StatementInformation()
{
- return new StatementInformation()
- {
- Name = s.Key.Name,
- SearchMode = s.Key.SearchMode,
- SpaceAround = s.Key.SpaceAround,
- Color = s.Key.Color,
- IgnoreSyntaxHighlighting = s.Key.IgnoreSyntaxHighlighting,
- Seperator = s.Key.Seperator
- };
- }).ToList();
+ Name = s.Key.Name,
+ SearchMode = s.Key.SearchMode,
+ SpaceAround = s.Key.SpaceAround,
+ Color = s.Key.Color,
+ IgnoreSyntaxHighlighting = s.Key.IgnoreSyntaxHighlighting,
+ Seperator = s.Key.Seperator
+ };
+ }).ToList();
- return new ReadOnlyCollection(informations);
- }
+ return new ReadOnlyCollection(informations);
}
+ }
- public event Action OnLineExecuted;
+ public event Action OnLineExecuted;
- public event Action OnDebugOutput;
+ public event Action OnDebugOutput;
- public void Stop()
+ public void Stop()
+ {
+ runtimeInfo.Exit("Terminated by external process", true);
+ }
+
+ public void Initialize()
+ {
+ Assembly assembly = Assembly.GetExecutingAssembly();
+ Type[] types = assembly.GetTypes();
+
+ IEnumerable statementRuntimeInfos = types.Where(t => t.IsSubclassOf(typeof(StatementRuntimeInformation)));
+
+ statements.Clear();
+
+ foreach (Type type in statementRuntimeInfos)
{
- runtimeInfo.Exit("Terminated by external process", true);
- }
+ object statementInfo = Activator.CreateInstance(type);
- public void Initialize()
- {
- Assembly assembly = Assembly.GetExecutingAssembly();
- Type[] types = assembly.GetTypes();
+ MethodInfo[] methodInfos = statementInfo.GetType().GetMethods();
- IEnumerable statementRuntimeInfos = types.Where(t => t.IsSubclassOf(typeof(StatementRuntimeInformation)));
+ StatementRuntimeInformation statementRuntimeInfo = statementInfo as StatementRuntimeInformation;
+ statementRuntimeInfo.RuntimeInfo = runtimeInfo;
- statements.Clear();
-
- foreach (Type type in statementRuntimeInfos)
+ foreach (MethodInfo methodInfo in methodInfos)
{
- object statementInfo = Activator.CreateInstance(type);
-
- MethodInfo[] methodInfos = statementInfo.GetType().GetMethods();
-
- StatementRuntimeInformation statementRuntimeInfo = statementInfo as StatementRuntimeInformation;
- statementRuntimeInfo.RuntimeInfo = runtimeInfo;
-
- foreach (MethodInfo methodInfo in methodInfos)
+ StatementAttribute statementAttribute = methodInfo.GetCustomAttribute();
+ if (statementAttribute is not null)
{
- StatementAttribute statementAttribute = methodInfo.GetCustomAttribute();
- if (statementAttribute is not null)
- {
- Action method = methodInfo.CreateDelegate(typeof(Action), statementInfo) as Action;
- statements.Add(statementAttribute, method);
- }
+ Action method = methodInfo.CreateDelegate(typeof(Action), statementInfo) as Action;
+ statements.Add(statementAttribute, method);
+ }
- StaticStatementAttribute staticStatementAttribute = methodInfo.GetCustomAttribute();
- if (staticStatementAttribute is not null)
- {
- Action method = methodInfo.CreateDelegate(typeof(Action), statementInfo) as Action;
- staticStatements.Add(new(staticStatementAttribute, method));
- }
+ StaticStatementAttribute staticStatementAttribute = methodInfo.GetCustomAttribute();
+ if (staticStatementAttribute is not null)
+ {
+ Action method = methodInfo.CreateDelegate(typeof(Action), statementInfo) as Action;
+ staticStatements.Add(new(staticStatementAttribute, method));
}
}
-
- statements = statements.OrderBy(s => s.Key.Priority).ToDictionary(x => x.Key, x => x.Value);
- staticStatements = staticStatements.OrderBy(s => s.Key.Priority).ToList();
-
- runtimeInfo.OnDebugOutput += (s) => OnDebugOutput?.Invoke(s);
- runtimeInfo.OnLineExecuted += (DebugEventArgs e) => OnLineExecuted?.Invoke(e);
}
- public void Execute(string path, bool isDebugMode = false)
+ statements = statements.OrderBy(s => s.Key.Priority).ToDictionary(x => x.Key, x => x.Value);
+ staticStatements = staticStatements.OrderBy(s => s.Key.Priority).ToList();
+
+ runtimeInfo.OnDebugOutput += (s) => OnDebugOutput?.Invoke(s);
+ runtimeInfo.OnLineExecuted += (DebugEventArgs e) => OnLineExecuted?.Invoke(e);
+ }
+
+ public void Execute(string path, bool isDebugMode = false)
+ {
+ runtimeInfo.Reset();
+ runtimeInfo.IsDebugMode = isDebugMode;
+ if (LoadFile(path))
{
- runtimeInfo.Reset();
- runtimeInfo.IsDebugMode = isDebugMode;
- if (LoadFile(path))
- {
- Execute();
- }
- }
-
- public void Execute(List lines, bool isDebugMode = false)
- {
- runtimeInfo.Reset();
- runtimeInfo.IsDebugMode = isDebugMode;
-
- for (int i = 0; i < lines.Count; i++)
- {
- runtimeInfo.Lines.Add(new Line(lines[i], Path.GetFileName("#Memory#"), i));
- }
-
Execute();
}
+ }
- internal void Execute(List lines, Dictionary gloablVariables, int startLine, RuntimeInformation parentRuntimeInformation)
+ public void Execute(List lines, bool isDebugMode = false)
+ {
+ runtimeInfo.Reset();
+ runtimeInfo.IsDebugMode = isDebugMode;
+
+ for (int i = 0; i < lines.Count; i++)
{
- runtimeInfo.Reset();
- runtimeInfo.IsDebugMode = parentRuntimeInformation.IsDebugMode;
- runtimeInfo.Lines = lines;
- runtimeInfo.LineNumber = startLine;
- runtimeInfo.ParentRuntimeInformation = parentRuntimeInformation;
- runtimeInfo.GloablVariables = gloablVariables;
- if (parentRuntimeInformation.StopAllTasks)
- {
- runtimeInfo.Exit($"Parent task was terminated!", parentRuntimeInformation.StopAllTasks);
- return;
- }
- Execute();
+ runtimeInfo.Lines.Add(new Line(lines[i], Path.GetFileName("#Memory#"), i));
}
- private void Execute()
+ Execute();
+ }
+
+ internal void Execute(List lines, Dictionary gloablVariables, int startLine, RuntimeInformation parentRuntimeInformation)
+ {
+ runtimeInfo.Reset();
+ runtimeInfo.IsDebugMode = parentRuntimeInformation.IsDebugMode;
+ runtimeInfo.Lines = lines;
+ runtimeInfo.LineNumber = startLine;
+ runtimeInfo.ParentRuntimeInformation = parentRuntimeInformation;
+ runtimeInfo.GloablVariables = gloablVariables;
+ if (parentRuntimeInformation.StopAllTasks)
{
- for (; runtimeInfo.LineNumber < runtimeInfo.Lines.Count; runtimeInfo.LineNumber++)
+ runtimeInfo.Exit($"Parent task was terminated!", parentRuntimeInformation.StopAllTasks);
+ return;
+ }
+ Execute();
+ }
+
+ private void Execute()
+ {
+ for (; runtimeInfo.LineNumber < runtimeInfo.Lines.Count; runtimeInfo.LineNumber++)
+ {
+ if (runtimeInfo.Stop)
{
+ break;
+ }
+
+ runtimeInfo.CurrentLine = runtimeInfo.Lines[runtimeInfo.LineNumber].Content.TrimEnd().Replace("\r", string.Empty);
+
+ if (string.IsNullOrWhiteSpace(runtimeInfo.CurrentLine) || runtimeInfo.CurrentLine.StartsWith('#'))
+ {
+ continue;
+ }
+
+ DebugEventArgs debugEventArgs = new DebugEventArgs()
+ {
+ LineNumber = runtimeInfo.LineNumber + 1,
+ OriginalLine = runtimeInfo.CurrentLine.FromSafeString(),
+ IsTask = runtimeInfo.IsTask,
+ TaskId = runtimeInfo.TaskId
+ };
+
+ foreach (KeyValuePair staticStatement in staticStatements)
+ {
+ StaticStatementAttribute staticStatementAttribute = staticStatement.Key;
+ if (!staticStatementAttribute.ExecuteInSearchMode && runtimeInfo.IsSearching)
+ {
+ continue;
+ }
+
+ staticStatement.Value.Invoke();
+ }
+
+ bool statementFound = false;
+ bool notSearchingLabel = !runtimeInfo.IsSearching;
+
+ foreach (KeyValuePair> statement in statements)
+ {
+ StatementAttribute statementAttribute = statement.Key;
+
+ if (!statementAttribute.ExecuteInSearchMode && runtimeInfo.IsSearching)
+ {
+ statementFound = true;
+ continue;
+ }
+
if (runtimeInfo.Stop)
{
break;
}
- runtimeInfo.CurrentLine = runtimeInfo.Lines[runtimeInfo.LineNumber].Content.TrimEnd().Replace("\r", string.Empty);
-
- if (string.IsNullOrWhiteSpace(runtimeInfo.CurrentLine) || runtimeInfo.CurrentLine.StartsWith('#'))
+ string name = statementAttribute.SpaceAround switch
{
- continue;
- }
-
- DebugEventArgs debugEventArgs = new DebugEventArgs()
- {
- LineNumber = runtimeInfo.LineNumber + 1,
- OriginalLine = runtimeInfo.CurrentLine.FromSafeString(),
- IsTask = runtimeInfo.IsTask,
- TaskId = runtimeInfo.TaskId
+ SpaceAround.StartEnd => $" {statementAttribute.Name.Trim()} ",
+ SpaceAround.Start => $" {statementAttribute.Name.Trim()}",
+ SpaceAround.End => $"{statementAttribute.Name.Trim()} ",
+ _ => statementAttribute.Name
};
- foreach (KeyValuePair staticStatement in staticStatements)
+ if (statementAttribute.Seperator is null || runtimeInfo.CurrentLine.Contains(statementAttribute.Seperator))
{
- StaticStatementAttribute staticStatementAttribute = staticStatement.Key;
- if (!staticStatementAttribute.ExecuteInSearchMode && runtimeInfo.IsSearching)
- {
- continue;
- }
-
- staticStatement.Value.Invoke();
- }
-
- bool statementFound = false;
- bool notSearchingLabel = !runtimeInfo.IsSearching;
-
- foreach (KeyValuePair> statement in statements)
- {
- StatementAttribute statementAttribute = statement.Key;
-
- if (!statementAttribute.ExecuteInSearchMode && runtimeInfo.IsSearching)
+ if (statementAttribute.SearchMode == SearchMode.StartOfLine && runtimeInfo.CurrentLine.StartsWith(name))
{
+ string copyLine = statementAttribute.KeepStatementInArgs ? runtimeInfo.CurrentLine : runtimeInfo.CurrentLine.Remove(0, name.Length);
+ statement.Value.Invoke(copyLine);
statementFound = true;
- continue;
}
-
- if (runtimeInfo.Stop)
+ else if (statementAttribute.SearchMode == SearchMode.Contains && $" {runtimeInfo.CurrentLine} ".Contains(name))
{
- break;
+ bool leadingWhitespace = runtimeInfo.CurrentLine.StartsWith(' ');
+
+ runtimeInfo.CurrentLine = $" {runtimeInfo.CurrentLine} ";
+ string copyLine = statementAttribute.KeepStatementInArgs ? runtimeInfo.CurrentLine : runtimeInfo.CurrentLine.Replace(name, string.Empty);
+ statement.Value.Invoke(copyLine);
+ statementFound = true;
+
+ runtimeInfo.CurrentLine = !leadingWhitespace ? runtimeInfo.CurrentLine.Trim() : runtimeInfo.CurrentLine.TrimEnd();
}
-
- string name = statementAttribute.SpaceAround switch
+ else if (statementAttribute.SearchMode == SearchMode.EndOfLine && runtimeInfo.CurrentLine.EndsWith(name))
{
- SpaceAround.StartEnd => $" {statementAttribute.Name.Trim()} ",
- SpaceAround.Start => $" {statementAttribute.Name.Trim()}",
- SpaceAround.End => $"{statementAttribute.Name.Trim()} ",
- _ => statementAttribute.Name
- };
-
- if (statementAttribute.Seperator is null || runtimeInfo.CurrentLine.Contains(statementAttribute.Seperator))
+ string copyLine = statementAttribute.KeepStatementInArgs ? runtimeInfo.CurrentLine : runtimeInfo.CurrentLine.Remove(runtimeInfo.CurrentLine.Length - name.Length);
+ statement.Value.Invoke(copyLine);
+ statementFound = true;
+ }
+ else if (statementAttribute.SearchMode == SearchMode.Exact && runtimeInfo.CurrentLine.Equals(name))
{
- if (statementAttribute.SearchMode == SearchMode.StartOfLine && runtimeInfo.CurrentLine.StartsWith(name))
- {
- string copyLine = statementAttribute.KeepStatementInArgs ? runtimeInfo.CurrentLine : runtimeInfo.CurrentLine.Remove(0, name.Length);
- statement.Value.Invoke(copyLine);
- statementFound = true;
- }
- else if (statementAttribute.SearchMode == SearchMode.Contains && $" {runtimeInfo.CurrentLine} ".Contains(name))
- {
- bool leadingWhitespace = runtimeInfo.CurrentLine.StartsWith(' ');
-
- runtimeInfo.CurrentLine = $" {runtimeInfo.CurrentLine} ";
- string copyLine = statementAttribute.KeepStatementInArgs ? runtimeInfo.CurrentLine : runtimeInfo.CurrentLine.Replace(name, string.Empty);
- statement.Value.Invoke(copyLine);
- statementFound = true;
-
- runtimeInfo.CurrentLine = !leadingWhitespace ? runtimeInfo.CurrentLine.Trim() : runtimeInfo.CurrentLine.TrimEnd();
- }
- else if (statementAttribute.SearchMode == SearchMode.EndOfLine && runtimeInfo.CurrentLine.EndsWith(name))
- {
- string copyLine = statementAttribute.KeepStatementInArgs ? runtimeInfo.CurrentLine : runtimeInfo.CurrentLine.Remove(runtimeInfo.CurrentLine.Length - name.Length);
- statement.Value.Invoke(copyLine);
- statementFound = true;
- }
- else if (statementAttribute.SearchMode == SearchMode.Exact && runtimeInfo.CurrentLine.Equals(name))
- {
- statement.Value.Invoke(runtimeInfo.CurrentLine);
- statementFound = true;
- }
+ statement.Value.Invoke(runtimeInfo.CurrentLine);
+ statementFound = true;
}
- }
-
- if (!statementFound)
- {
- runtimeInfo.Exit("Invalid statement", true);
- }
- if (runtimeInfo.IsDebugMode && notSearchingLabel)
- {
- debugEventArgs.CurrentLine = runtimeInfo.CurrentLine.FromSafeString();
- runtimeInfo.LineExecuted(debugEventArgs);
}
}
- if (!runtimeInfo.Stop)
+ if (!statementFound)
{
- if (!string.IsNullOrWhiteSpace(runtimeInfo.SearchLabel))
- {
- runtimeInfo.Exit($"Label \"{runtimeInfo.SearchLabel}\" not found", true);
- }
- else if (!string.IsNullOrWhiteSpace(runtimeInfo.SearchFunction))
- {
- runtimeInfo.Exit($"Function \"{runtimeInfo.SearchFunction}\" not found", true);
- }
- else
- {
- runtimeInfo.Exit("End of file", false);
- }
-
- if (runtimeInfo.IsDebugMode)
- {
- runtimeInfo.LineExecuted(null);
- }
+ runtimeInfo.Exit("Invalid statement", true);
+ }
+ if (runtimeInfo.IsDebugMode && notSearchingLabel)
+ {
+ debugEventArgs.CurrentLine = runtimeInfo.CurrentLine.FromSafeString();
+ runtimeInfo.LineExecuted(debugEventArgs);
}
}
- private bool LoadFile(string path)
+ if (!runtimeInfo.Stop)
{
- path = Path.GetFullPath(path);
-
- if (!File.Exists(path))
+ if (!string.IsNullOrWhiteSpace(runtimeInfo.SearchLabel))
{
- Console.WriteLine($"File \"{path}\" not found!");
- return false;
+ runtimeInfo.Exit($"Label \"{runtimeInfo.SearchLabel}\" not found", true);
+ }
+ else if (!string.IsNullOrWhiteSpace(runtimeInfo.SearchFunction))
+ {
+ runtimeInfo.Exit($"Function \"{runtimeInfo.SearchFunction}\" not found", true);
+ }
+ else
+ {
+ runtimeInfo.Exit("End of file", false);
}
- string[] lines = File.ReadAllLines(path);
-
- if (lines.Length <= 0)
+ if (runtimeInfo.IsDebugMode)
{
- Console.WriteLine($"File \"{path}\" is empty!");
- return false;
+ runtimeInfo.LineExecuted(null);
}
-
- runtimeInfo.WorkingDirectory = Path.GetDirectoryName(path);
-
- for (int i = 0; i < lines.Length; i++)
- {
- runtimeInfo.Lines.Add(new Line(lines[i], Path.GetFileName(path), i));
- }
-
- return true;
}
}
+
+ private bool LoadFile(string path)
+ {
+ path = Path.GetFullPath(path);
+
+ if (!File.Exists(path))
+ {
+ Console.WriteLine($"File \"{path}\" not found!");
+ return false;
+ }
+
+ string[] lines = File.ReadAllLines(path);
+
+ if (lines.Length <= 0)
+ {
+ Console.WriteLine($"File \"{path}\" is empty!");
+ return false;
+ }
+
+ runtimeInfo.WorkingDirectory = Path.GetDirectoryName(path);
+
+ for (int i = 0; i < lines.Length; i++)
+ {
+ runtimeInfo.Lines.Add(new Line(lines[i], Path.GetFileName(path), i));
+ }
+
+ return true;
+ }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Statements/ConsoleStatements.cs b/YesNt.Interpreter/Statements/ConsoleStatements.cs
index 574df89..d0bd322 100644
--- a/YesNt.Interpreter/Statements/ConsoleStatements.cs
+++ b/YesNt.Interpreter/Statements/ConsoleStatements.cs
@@ -6,56 +6,61 @@ using YesNt.Interpreter.Enums;
using YesNt.Interpreter.Runtime;
using YesNt.Interpreter.Utilities;
-namespace YesNt.Interpreter.Statements
+namespace YesNt.Interpreter.Statements;
+
+internal class ConsoleStatements : StatementRuntimeInformation
{
- internal class ConsoleStatements : StatementRuntimeInformation
+ [Statement("cwl", SearchMode.Exact, SpaceAround.None, ConsoleColor.DarkGreen, Priority = Priority.VeryLow)]
+ public void WriteLineEmpty(string _)
{
- [Statement("cwl", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkGreen, Priority = Priority.VeryLow)]
- public void WriteLine(string args)
- {
- RuntimeInfo.WriteLine(args);
- }
+ RuntimeInfo.WriteLine(string.Empty);
+ }
- [Statement("cw", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkGreen, Priority = Priority.VeryLow)]
- public void Write(string args)
- {
- RuntimeInfo.Write(args);
- }
+ [Statement("cwl", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkGreen, Priority = Priority.VeryLow)]
+ public void WriteLine(string args)
+ {
+ RuntimeInfo.WriteLine(args);
+ }
- [Statement("%crl", SearchMode.Contains, SpaceAround.End, ConsoleColor.DarkGreen, KeepStatementInArgs = true, Priority = Priority.Highest)]
- public void ReadLine(string args)
+ [Statement("cw", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkGreen, Priority = Priority.VeryLow)]
+ public void Write(string args)
+ {
+ RuntimeInfo.Write(args);
+ }
+
+ [Statement("%crl", SearchMode.Contains, SpaceAround.End, ConsoleColor.DarkGreen, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ public void ReadLine(string args)
+ {
+ args += " ";
+ while (args.Contains("%crl "))
{
- args += " ";
- while (args.Contains("%crl "))
+ string input = Console.ReadLine();
+ if (input is null)
{
- string input = Console.ReadLine();
- if (input is null)
- {
- RuntimeInfo.Exit("Terminated by external process", true);
- return;
- }
- args = args.ReplaceFirstOccurrence("%crl ", input.ToSafeString() + " ");
+ RuntimeInfo.Exit("Terminated by external process", true);
+ return;
}
- RuntimeInfo.CurrentLine = args.TrimEnd();
+ args = args.ReplaceFirstOccurrence("%crl ", input.ToSafeString() + " ");
}
+ RuntimeInfo.CurrentLine = args.TrimEnd();
+ }
- [Statement("%cr", SearchMode.Contains, SpaceAround.End, ConsoleColor.DarkGreen, KeepStatementInArgs = true, Priority = Priority.Highest)]
- public void ReadKey(string args)
+ [Statement("%cr", SearchMode.Contains, SpaceAround.End, ConsoleColor.DarkGreen, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ public void ReadKey(string args)
+ {
+ args += " ";
+ while (args.Contains("%cr "))
{
- args += " ";
- while (args.Contains("%cr "))
- {
- string input = ConsoleExtentions.ReadKey(RuntimeInfo).ToString();
- args = args.ReplaceFirstOccurrence("%cr ", input.ToSafeString() + " ");
- }
- RuntimeInfo.CurrentLine = args.TrimEnd();
+ string input = ConsoleExtentions.ReadKey(RuntimeInfo).ToString();
+ args = args.ReplaceFirstOccurrence("%cr ", input.ToSafeString() + " ");
}
+ RuntimeInfo.CurrentLine = args.TrimEnd();
+ }
- [Statement("cls", SearchMode.Exact, SpaceAround.None, ConsoleColor.Magenta)]
- [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Won't work if static")]
- public void Clear(string _)
- {
- Console.Clear();
- }
+ [Statement("cls", SearchMode.Exact, SpaceAround.None, ConsoleColor.Magenta)]
+ [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Won't work if static")]
+ public void Clear(string _)
+ {
+ Console.Clear();
}
}
\ No newline at end of file
From 79df5c9b97f36c7fc701118a94b0a421d8f3336f Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 27 Sep 2023 12:15:38 +0200
Subject: [PATCH 10/73] Many improvements and bug fixes
---
YesNt.CodeEditor/SyntaxHighlighter.cs | 37 ++-
YesNt.Interpreter/Runtime/FunctionScope.cs | 27 +-
.../Runtime/RuntimeInformation.cs | 296 +++++++++---------
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 28 +-
.../Statements/ConsoleStatements.cs | 8 +-
.../Statements/ProcessingStatements.cs | 9 +
.../Statements/VariableStatements.cs | 28 +-
.../Utilities/StringExtentions.cs | 8 +-
8 files changed, 228 insertions(+), 213 deletions(-)
diff --git a/YesNt.CodeEditor/SyntaxHighlighter.cs b/YesNt.CodeEditor/SyntaxHighlighter.cs
index b69420d..7ef4d22 100644
--- a/YesNt.CodeEditor/SyntaxHighlighter.cs
+++ b/YesNt.CodeEditor/SyntaxHighlighter.cs
@@ -17,6 +17,18 @@ internal partial class SyntaxHighlighter
this.statementInformation = statementInformation;
}
+ public static string Base64Encode(string plainText)
+ {
+ byte[] plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
+ return System.Convert.ToBase64String(plainTextBytes);
+ }
+
+ public static string Base64Decode(string base64EncodedData)
+ {
+ byte[] base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
+ return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
+ }
+
public void Write(string input)
{
input = input.Replace("\0", string.Empty);
@@ -30,7 +42,7 @@ internal partial class SyntaxHighlighter
MatchCollection matches = EscapeSequenceRegex().Matches(input);
for (int i = 0; i < matches.Count; i++)
{
- input = AddColorInformation(input, matches[i].Value, Console.ForegroundColor, SearchMode.Contains);
+ input = AddColorInformation(input, matches[i].Value, ConsoleColor.DarkYellow, SearchMode.Contains);
}
foreach (StatementInformation statement in statementInformation)
@@ -45,9 +57,9 @@ internal partial class SyntaxHighlighter
SpaceAround.StartEnd => $" {statement.Name.Trim()} ",
SpaceAround.Start => $" {statement.Name.Trim()}",
SpaceAround.End => $"{statement.Name.Trim()} ",
- _ => statement.Name
+ _ => statement.Name.Trim()
};
- input = input.TrimEnd();
+ input = input.TrimEnd(' ');
if (statement.SearchMode == SearchMode.StartOfLine && input.StartsWith(name))
{
if (statement.Seperator is not null && input.Contains(statement.Seperator))
@@ -60,7 +72,7 @@ internal partial class SyntaxHighlighter
}
input = AddColorInformation(input, input[..name.Length], statement.Color, statement.SearchMode);
}
- if (statement.SearchMode == SearchMode.Contains && $" {input} ".Contains(name))
+ else if (statement.SearchMode == SearchMode.Contains && input.Contains(name))
{
if (statement.Seperator is not null && input.Contains(statement.Seperator))
{
@@ -70,9 +82,9 @@ internal partial class SyntaxHighlighter
{
continue;
}
- input = AddColorInformation($"{input} ", $"{input} ".Substring($"{input} ".IndexOf(name), name.Length), statement.Color, statement.SearchMode);
+ input = AddColorInformation(input, input.Substring(input.IndexOf(name), name.Length), statement.Color, statement.SearchMode);
}
- if (statement.SearchMode == SearchMode.EndOfLine && input.EndsWith(name))
+ else if (statement.SearchMode == SearchMode.EndOfLine && input.EndsWith(name))
{
if (statement.Seperator is not null && input.Contains(statement.Seperator))
{
@@ -84,7 +96,7 @@ internal partial class SyntaxHighlighter
}
input = AddColorInformation(input, input[^name.Length..], statement.Color, statement.SearchMode);
}
- if (statement.SearchMode == SearchMode.Exact && input.Equals(name))
+ else if (statement.SearchMode == SearchMode.Exact && input.Equals(name))
{
if (statement.Seperator is not null && input.Contains(statement.Seperator))
{
@@ -126,7 +138,7 @@ internal partial class SyntaxHighlighter
bool succ = int.TryParse(stringColor, out int colorIndex);
if (succ && colorIndex >= 0 && colorIndex < 16)
{
- messagePart = messagePart.Replace($"\r{stringColor}\r", string.Empty);
+ messagePart = Base64Decode(messagePart.Replace($"\r{stringColor}\r", string.Empty));
consoleColor = (ConsoleColor)colorIndex;
}
else
@@ -147,11 +159,14 @@ internal partial class SyntaxHighlighter
private static string AddColorInformation(string originalString, string value, ConsoleColor color, SearchMode searchMode)
{
int spacesAtEnd = value.WhiteSpaceAtEnd();
+
+ string base64Value = Base64Encode(value.TrimEnd());
+
string reult = searchMode switch
{
- SearchMode.StartOfLine => originalString.ReplaceFirstOccurrence(value, $"\0\r{(int)color}\r{value.TrimEnd()}\0" + new string(' ', spacesAtEnd)),
- SearchMode.EndOfLine => originalString.ReplaceLastOccurrence(value, $"\0\r{(int)color}\r{value.TrimEnd()}\0" + new string(' ', spacesAtEnd)),
- _ => originalString.Replace(value, $"\0\r{(int)color}\r{value.TrimEnd()}\0" + new string(' ', spacesAtEnd))
+ SearchMode.StartOfLine => originalString.ReplaceFirstOccurrence(value, $"\0\r{(int)color}\r{base64Value}\0" + new string(' ', spacesAtEnd)),
+ SearchMode.EndOfLine => originalString.ReplaceLastOccurrence(value, $"\0\r{(int)color}\r{base64Value}\0" + new string(' ', spacesAtEnd)),
+ _ => originalString.Replace(value, $"\0\r{(int)color}\r{base64Value}\0" + new string(' ', spacesAtEnd))
};
return reult;
}
diff --git a/YesNt.Interpreter/Runtime/FunctionScope.cs b/YesNt.Interpreter/Runtime/FunctionScope.cs
index ed9acf9..9b58e0c 100644
--- a/YesNt.Interpreter/Runtime/FunctionScope.cs
+++ b/YesNt.Interpreter/Runtime/FunctionScope.cs
@@ -1,19 +1,18 @@
using System.Collections.Generic;
-namespace YesNt.Interpreter.Runtime
-{
- internal class FunctionScope
- {
- public int CallerLine { get; }
- public Dictionary Variables { get; } = new();
- public Dictionary Labels { get; } = new();
- public Stack Arguemtns { get; }
- public Stack Results { get; } = new();
+namespace YesNt.Interpreter.Runtime;
- public FunctionScope(int callerLine, Stack arguemtns)
- {
- CallerLine = callerLine;
- Arguemtns = arguemtns;
- }
+internal class FunctionScope
+{
+ public int CallerLine { get; }
+ public Dictionary Variables { get; } = new();
+ public Dictionary Labels { get; } = new();
+ public Stack Arguemtns { get; }
+ public Stack Results { get; } = new();
+
+ public FunctionScope(int callerLine, Stack arguemtns)
+ {
+ CallerLine = callerLine;
+ Arguemtns = arguemtns;
}
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Runtime/RuntimeInformation.cs b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
index 2e70a69..c04e697 100644
--- a/YesNt.Interpreter/Runtime/RuntimeInformation.cs
+++ b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
@@ -1,181 +1,177 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using YesNt.Interpreter.Utilities;
-namespace YesNt.Interpreter.Runtime
+namespace YesNt.Interpreter.Runtime;
+
+internal sealed class RuntimeInformation
{
- internal sealed class RuntimeInformation
+ public event Action OnDebugOutput;
+
+ public event Action OnLineExecuted;
+
+ private event Action OnExit;
+
+ private static int internalTaskId = 0;
+ private readonly Dictionary topVariables = new();
+ private readonly Dictionary topLabels = new();
+ private RuntimeInformation parentRuntimeInformation;
+ private int taskId = 0;
+ public Dictionary GloablVariables { get; set; } = new();
+ public Dictionary Functions { get; } = new();
+ public Stack FunctionCallStack { get; } = new();
+ public Stack InParametersStack { get; } = new();
+ public Stack OutParametersStack { get; set; } = new();
+ public List Lines { get; set; } = new();
+ public string CurrentLine { get; set; } = string.Empty;
+ public string SearchLabel { get; set; } = string.Empty;
+ public string SearchFunction { get; set; } = string.Empty;
+ public int LineNumber { get; set; } = 0;
+ public bool Stop { get; private set; } = false;
+ public bool StopAllTasks { get; private set; } = false;
+ public bool IsDebugMode { get; set; } = false;
+ public string WorkingDirectory { get; set; } = string.Empty;
+ public bool IsTask => ParentRuntimeInformation is not null;
+ public int TaskId => IsTask ? taskId : 0;
+ public bool InternalIsInFunction { get; set; }
+
+ public bool IsInFunction
{
- private RuntimeInformation parentRuntimeInformation;
- private static int internalTaskId = 0;
- private int taskId = 0;
+ get => InternalIsInFunction || FunctionCallStack.Count > 0;
+ set => InternalIsInFunction = value;
+ }
- private readonly Dictionary topVariables = new();
- private readonly Dictionary topLabels = new();
+ public Dictionary Variables => FunctionCallStack.Count == 0 ? topVariables : FunctionCallStack.Peek().Variables;
- public Dictionary GloablVariables { get; set; } = new();
- public Dictionary Functions { get; } = new();
- public Stack FunctionCallStack { get; } = new();
- public Stack InParametersStack { get; } = new();
- public Stack OutParametersStack { get; set; } = new();
- public List Lines { get; set; } = new();
- public string CurrentLine { get; set; } = string.Empty;
- public string SearchLabel { get; set; } = string.Empty;
- public string SearchFunction { get; set; } = string.Empty;
- public int LineNumber { get; set; } = 0;
- public bool Stop { get; private set; } = false;
- public bool StopAllTasks { get; private set; } = false;
- public bool IsDebugMode { get; set; } = false;
- public string WorkingDirectory { get; set; } = string.Empty;
- public bool IsTask => ParentRuntimeInformation is not null;
- public int TaskId => IsTask ? taskId : 0;
- public bool InternalIsInFunction { get; set; }
+ public Dictionary Labels => FunctionCallStack.Count == 0 ? topLabels : FunctionCallStack.Peek().Labels;
- public bool IsInFunction
+ public RuntimeInformation ParentRuntimeInformation
+ {
+ get => parentRuntimeInformation;
+ set
{
- get => InternalIsInFunction || FunctionCallStack.Count > 0;
- set => InternalIsInFunction = value;
- }
-
- public Dictionary Variables => FunctionCallStack.Count == 0 ? topVariables : FunctionCallStack.Peek().Variables;
-
- public Dictionary Labels => FunctionCallStack.Count == 0 ? topLabels : FunctionCallStack.Peek().Labels;
-
- public RuntimeInformation ParentRuntimeInformation
- {
- get => parentRuntimeInformation;
- set
+ parentRuntimeInformation = value;
+ if (parentRuntimeInformation is not null)
{
- parentRuntimeInformation = value;
- if (parentRuntimeInformation is not null)
- {
- parentRuntimeInformation.OnExit += ParentRuntimeInformation_OnExit;
- }
+ parentRuntimeInformation.OnExit += ParentRuntimeInformation_OnExit;
}
}
+ }
- public bool IsSearching => !string.IsNullOrWhiteSpace(SearchLabel + SearchFunction) || (IsInFunction && FunctionCallStack.Count == 0);
- public bool IsLocalSearch { get; set; }
+ public bool IsSearching => !string.IsNullOrWhiteSpace(SearchLabel + SearchFunction) || (IsInFunction && FunctionCallStack.Count == 0);
+ public bool IsLocalSearch { get; set; }
- private event Action OnExit;
-
- public event Action OnDebugOutput;
-
- public event Action OnLineExecuted;
-
- private void ParentRuntimeInformation_OnExit(string exitMessage, bool stopAllTasks)
+ public void WriteLine(string output, bool forceWrite = false)
+ {
+ if ((Stop && !forceWrite) || (parentRuntimeInformation?.StopAllTasks == true && !forceWrite))
{
- Exit($"Terminated by parent task", stopAllTasks);
+ return;
}
- public void WriteLine(string output, bool forceWrite = false)
- {
- if ((Stop && !forceWrite) || (parentRuntimeInformation?.StopAllTasks == true && !forceWrite))
- {
- return;
- }
-
- if (IsDebugMode)
- {
- if (IsTask)
- {
- parentRuntimeInformation!.WriteLine(output.FromSafeString(), forceWrite);
- }
- else
- {
- OnDebugOutput?.Invoke(output.FromSafeString() + Environment.NewLine);
- }
- }
- else
- {
- Console.WriteLine(output.FromSafeString());
- }
- }
-
- public void Write(string output, bool forceWrite = false)
- {
- if ((Stop && !forceWrite) || (parentRuntimeInformation?.StopAllTasks == true && !forceWrite))
- {
- return;
- }
-
- if (IsDebugMode)
- {
- if (IsTask)
- {
- parentRuntimeInformation!.Write(output.FromSafeString(), forceWrite);
- }
- else
- {
- OnDebugOutput?.Invoke(output.FromSafeString());
- }
- }
- else
- {
- Console.Write(output.FromSafeString());
- }
- }
-
- public void Exit(string message, bool stopAllTasks)
- {
- if (!Stop)
- {
- Line line = Lines[Math.Min(LineNumber, Lines.Count - 1)];
- WriteLine($"{Environment.NewLine}[{(IsTask ? $"Task {TaskId}" : "The process")} was terminated at line {line.LineNumber + 1} in the file \"{line.FileName}\" with the message: {message}]", true);
- while (FunctionCallStack.Count > 0)
- {
- int stackLineNumber = FunctionCallStack.Pop().CallerLine;
- Line stackLine = (ParentRuntimeInformation?.Lines ?? Lines).ElementAt(stackLineNumber);
- WriteLine($" at line {stackLine.LineNumber + 1} in the file \"{stackLine.FileName}\"", true);
- }
-
- Stop = true;
- }
- if (stopAllTasks && !StopAllTasks)
- {
- StopAllTasks = true;
- OnExit?.Invoke(message, StopAllTasks);
- parentRuntimeInformation?.Exit("Terminated by child task", true);
- }
- }
-
- public void LineExecuted(DebugEventArgs debugEventArgs)
+ if (IsDebugMode)
{
if (IsTask)
{
- parentRuntimeInformation.LineExecuted(debugEventArgs);
+ parentRuntimeInformation!.WriteLine(output.FromSafeString(), forceWrite);
}
else
{
- OnLineExecuted?.Invoke(debugEventArgs);
+ OnDebugOutput?.Invoke(output.FromSafeString() + Environment.NewLine);
}
}
-
- public void Reset()
+ else
{
- topVariables.Clear();
- Lines.Clear();
- GloablVariables.Clear();
- Labels.Clear();
- Functions.Clear();
- FunctionCallStack.Clear();
- ParentRuntimeInformation = null;
- SearchLabel = string.Empty;
- SearchFunction = string.Empty;
- WorkingDirectory = string.Empty;
- CurrentLine = string.Empty;
- Stop = false;
- StopAllTasks = false;
- IsDebugMode = false;
- IsInFunction = false;
- IsLocalSearch = false;
- LineNumber = 0;
- taskId = internalTaskId + 1;
-#pragma warning disable S2696 // Instance members should not write to "static" fields
- internalTaskId++;
-#pragma warning restore S2696 // Instance members should not write to "static" fields
+ Console.WriteLine(output.FromSafeString());
}
}
+
+ public void Write(string output, bool forceWrite = false)
+ {
+ if ((Stop && !forceWrite) || (parentRuntimeInformation?.StopAllTasks == true && !forceWrite))
+ {
+ return;
+ }
+
+ if (IsDebugMode)
+ {
+ if (IsTask)
+ {
+ parentRuntimeInformation!.Write(output.FromSafeString(), forceWrite);
+ }
+ else
+ {
+ OnDebugOutput?.Invoke(output.FromSafeString());
+ }
+ }
+ else
+ {
+ Console.Write(output.FromSafeString());
+ }
+ }
+
+ public void Exit(string message, bool stopAllTasks)
+ {
+ if (!Stop)
+ {
+ Line line = Lines[Math.Min(LineNumber, Lines.Count - 1)];
+ WriteLine($"{Environment.NewLine}[{(IsTask ? $"Task {TaskId}" : "The process")} was terminated at line {line.LineNumber + 1} in the file \"{line.FileName}\" with the message: {message}]", true);
+ while (FunctionCallStack.Count > 0)
+ {
+ int stackLineNumber = FunctionCallStack.Pop().CallerLine;
+ Line stackLine = (ParentRuntimeInformation?.Lines ?? Lines)[stackLineNumber];
+ WriteLine($" at line {stackLine.LineNumber + 1} in the file \"{stackLine.FileName}\"", true);
+ }
+
+ Stop = true;
+ }
+ if (stopAllTasks && !StopAllTasks)
+ {
+ 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()
+ {
+ topVariables.Clear();
+ Lines.Clear();
+ GloablVariables.Clear();
+ Labels.Clear();
+ Functions.Clear();
+ FunctionCallStack.Clear();
+ ParentRuntimeInformation = null;
+ SearchLabel = string.Empty;
+ SearchFunction = string.Empty;
+ WorkingDirectory = string.Empty;
+ CurrentLine = string.Empty;
+ Stop = false;
+ StopAllTasks = false;
+ IsDebugMode = false;
+ IsInFunction = false;
+ IsLocalSearch = false;
+ LineNumber = 0;
+ taskId = internalTaskId + 1;
+#pragma warning disable S2696 // Instance members should not write to "static" fields
+ internalTaskId++;
+#pragma warning restore S2696 // Instance members should not write to "static" fields
+ }
+
+ private void ParentRuntimeInformation_OnExit(string exitMessage, bool stopAllTasks)
+ {
+ Exit($"Terminated by parent task", stopAllTasks);
+ }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index 81974a0..d11659a 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -13,6 +13,10 @@ namespace YesNt.Interpreter.Runtime;
public class YesNtInterpreter
{
+ public event Action OnLineExecuted;
+
+ public event Action OnDebugOutput;
+
private readonly RuntimeInformation runtimeInfo = new RuntimeInformation();
private Dictionary> statements = new();
private List> staticStatements = new();
@@ -38,10 +42,6 @@ public class YesNtInterpreter
}
}
- public event Action OnLineExecuted;
-
- public event Action OnDebugOutput;
-
public void Stop()
{
runtimeInfo.Exit("Terminated by external process", true);
@@ -83,8 +83,13 @@ public class YesNtInterpreter
}
}
- statements = statements.OrderBy(s => s.Key.Priority).ToDictionary(x => x.Key, x => x.Value);
- staticStatements = staticStatements.OrderBy(s => s.Key.Priority).ToList();
+ statements = statements
+ .OrderBy(s => s.Key.Priority)
+ .ThenByDescending(s => s.Key.Name.Length)
+ .ToDictionary(x => x.Key, x => x.Value);
+ staticStatements = staticStatements
+ .OrderBy(s => s.Key.Priority)
+ .ToList();
runtimeInfo.OnDebugOutput += (s) => OnDebugOutput?.Invoke(s);
runtimeInfo.OnLineExecuted += (DebugEventArgs e) => OnLineExecuted?.Invoke(e);
@@ -138,7 +143,7 @@ public class YesNtInterpreter
break;
}
- runtimeInfo.CurrentLine = runtimeInfo.Lines[runtimeInfo.LineNumber].Content.TrimEnd().Replace("\r", string.Empty);
+ runtimeInfo.CurrentLine = runtimeInfo.Lines[runtimeInfo.LineNumber].Content.Trim(' ').Replace("\r", string.Empty);
if (string.IsNullOrWhiteSpace(runtimeInfo.CurrentLine) || runtimeInfo.CurrentLine.StartsWith('#'))
{
@@ -187,7 +192,7 @@ public class YesNtInterpreter
SpaceAround.StartEnd => $" {statementAttribute.Name.Trim()} ",
SpaceAround.Start => $" {statementAttribute.Name.Trim()}",
SpaceAround.End => $"{statementAttribute.Name.Trim()} ",
- _ => statementAttribute.Name
+ _ => statementAttribute.Name.Trim()
};
if (statementAttribute.Seperator is null || runtimeInfo.CurrentLine.Contains(statementAttribute.Seperator))
@@ -198,16 +203,11 @@ public class YesNtInterpreter
statement.Value.Invoke(copyLine);
statementFound = true;
}
- else if (statementAttribute.SearchMode == SearchMode.Contains && $" {runtimeInfo.CurrentLine} ".Contains(name))
+ else if (statementAttribute.SearchMode == SearchMode.Contains && runtimeInfo.CurrentLine.Contains(name))
{
- bool leadingWhitespace = runtimeInfo.CurrentLine.StartsWith(' ');
-
- runtimeInfo.CurrentLine = $" {runtimeInfo.CurrentLine} ";
string copyLine = statementAttribute.KeepStatementInArgs ? runtimeInfo.CurrentLine : runtimeInfo.CurrentLine.Replace(name, string.Empty);
statement.Value.Invoke(copyLine);
statementFound = true;
-
- runtimeInfo.CurrentLine = !leadingWhitespace ? runtimeInfo.CurrentLine.Trim() : runtimeInfo.CurrentLine.TrimEnd();
}
else if (statementAttribute.SearchMode == SearchMode.EndOfLine && runtimeInfo.CurrentLine.EndsWith(name))
{
diff --git a/YesNt.Interpreter/Statements/ConsoleStatements.cs b/YesNt.Interpreter/Statements/ConsoleStatements.cs
index d0bd322..406db42 100644
--- a/YesNt.Interpreter/Statements/ConsoleStatements.cs
+++ b/YesNt.Interpreter/Statements/ConsoleStatements.cs
@@ -28,11 +28,11 @@ internal class ConsoleStatements : StatementRuntimeInformation
RuntimeInfo.Write(args);
}
- [Statement("%crl", SearchMode.Contains, SpaceAround.End, ConsoleColor.DarkGreen, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ [Statement("%crl", SearchMode.Contains, SpaceAround.None, ConsoleColor.DarkGreen, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void ReadLine(string args)
{
args += " ";
- while (args.Contains("%crl "))
+ while (args.Contains("%crl"))
{
string input = Console.ReadLine();
if (input is null)
@@ -45,11 +45,11 @@ internal class ConsoleStatements : StatementRuntimeInformation
RuntimeInfo.CurrentLine = args.TrimEnd();
}
- [Statement("%cr", SearchMode.Contains, SpaceAround.End, ConsoleColor.DarkGreen, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ [Statement("%cr", SearchMode.Contains, SpaceAround.None, ConsoleColor.DarkGreen, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void ReadKey(string args)
{
args += " ";
- while (args.Contains("%cr "))
+ while (args.Contains("%cr"))
{
string input = ConsoleExtentions.ReadKey(RuntimeInfo).ToString();
args = args.ReplaceFirstOccurrence("%cr ", input.ToSafeString() + " ");
diff --git a/YesNt.Interpreter/Statements/ProcessingStatements.cs b/YesNt.Interpreter/Statements/ProcessingStatements.cs
index 8c77aa8..0b5bd26 100644
--- a/YesNt.Interpreter/Statements/ProcessingStatements.cs
+++ b/YesNt.Interpreter/Statements/ProcessingStatements.cs
@@ -81,6 +81,15 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
ConsoleExtentions.Sleep(millisecondsTimeout, RuntimeInfo);
}
+ [Statement("len", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
+ public void Length(string args)
+ {
+ RuntimeInfo.InParametersStack.Clear();
+ RuntimeInfo.OutParametersStack.Clear();
+
+ RuntimeInfo.OutParametersStack.Push(args.FromSafeString().Length.ToString());
+ }
+
[Statement("imp", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
public void Import(string path)
{
diff --git a/YesNt.Interpreter/Statements/VariableStatements.cs b/YesNt.Interpreter/Statements/VariableStatements.cs
index 98eb57d..490512d 100644
--- a/YesNt.Interpreter/Statements/VariableStatements.cs
+++ b/YesNt.Interpreter/Statements/VariableStatements.cs
@@ -1,5 +1,4 @@
-using System.Collections.Generic;
-using System.Text.RegularExpressions;
+using System.Text.RegularExpressions;
using YesNt.Interpreter.Attributes;
using YesNt.Interpreter.Enums;
@@ -90,27 +89,20 @@ internal partial class VariableStatements : StatementRuntimeInformation
return;
}
- foreach (KeyValuePair variable in RuntimeInfo.Variables)
- {
- RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{variable.Key}", variable.Value);
- }
-
- foreach (KeyValuePair variable in RuntimeInfo.GloablVariables)
- {
- RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{variable.Key}", variable.Value);
- }
-
- if (RuntimeInfo.IsSearching)
- {
- return;
- }
-
MatchCollection matches = VariableStatementRegex().Matches(RuntimeInfo.CurrentLine);
for (int i = 0; i < matches.Count; i++)
{
string varName = matches[i].Value.Replace(">", string.Empty);
- if (!RuntimeInfo.Variables.ContainsKey(varName) && !RuntimeInfo.GloablVariables.ContainsKey(varName))
+ if (RuntimeInfo.Variables.TryGetValue(varName, out string value))
+ {
+ RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{varName}", value);
+ }
+ else if (RuntimeInfo.GloablVariables.TryGetValue(varName, out value))
+ {
+ RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{varName}", value);
+ }
+ else if (!RuntimeInfo.IsSearching)
{
RuntimeInfo.Exit($"Variable \"{varName}\" not found", true);
return;
diff --git a/YesNt.Interpreter/Utilities/StringExtentions.cs b/YesNt.Interpreter/Utilities/StringExtentions.cs
index c7a674a..06efe5f 100644
--- a/YesNt.Interpreter/Utilities/StringExtentions.cs
+++ b/YesNt.Interpreter/Utilities/StringExtentions.cs
@@ -13,12 +13,16 @@ public static class StringExtentions
{
_ = output.Append($"\v{c}\v");
}
- return output.ToString();
+ return output
+ .ToString()
+ .Replace(' ', '~');
}
public static string FromSafeString(this string input)
{
- return input.Replace("\v", "");
+ return input
+ .Replace("\v", "")
+ .Replace('~', ' ');
}
public static bool ToStandardizedNumber(this string input, out double result)
From ce3715c1b5482bd92fee5b0b8abf78a9fe1f472b Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 27 Sep 2023 17:17:28 +0200
Subject: [PATCH 11/73] Reformatting and reimperilment escape codes
---
YesNt.CodeEditor/Editor.cs | 446 +++++++-------
YesNt.CodeEditor/InputHandler.cs | 552 +++++++++---------
YesNt.CodeEditor/Program.cs | 15 +-
YesNt.CodeEditor/SyntaxHighlighter.cs | 13 +-
YesNt.Interpreter.Tests/CodeFowTests.cs | 3 +-
YesNt.Interpreter.Tests/YesNtAssert.cs | 22 +
.../Statements/ProcessingStatements.cs | 27 +-
.../Statements/VariableStatements.cs | 5 +
.../Utilities/StringExtentions.cs | 51 +-
9 files changed, 591 insertions(+), 543 deletions(-)
diff --git a/YesNt.CodeEditor/Editor.cs b/YesNt.CodeEditor/Editor.cs
index 54c92cb..7c8c08b 100644
--- a/YesNt.CodeEditor/Editor.cs
+++ b/YesNt.CodeEditor/Editor.cs
@@ -4,265 +4,263 @@ using System.IO;
using YesNt.Interpreter.Runtime;
-namespace YesNt.CodeEditor
+namespace YesNt.CodeEditor;
+
+internal class TextEditor
{
- internal class TextEditor
+ private readonly InputHandler inputHandler;
+ private readonly SyntaxHighlighter syntaxHighlighter;
+ private readonly List debugOutput = new();
+
+ private readonly Point oldSize = new Point(0, 0);
+ public YesNtInterpreter YesNtInterpreter { get; } = new();
+ public int LineOffset { get; set; } = 0;
+ public List Lines { get; } = new();
+ public Point CursorPosition { get; } = new(0, 0);
+ public Mode EditMode { get; set; } = Mode.Command;
+ public string CurrentPath { get; set; } = string.Empty;
+
+ public TextEditor(string path) : this()
{
- private readonly InputHandler inputHandler;
- private readonly SyntaxHighlighter syntaxHighlighter;
- private readonly List debugOutput = new();
-
- public YesNtInterpreter YesNtInterpreter { get; } = new();
- public int LineOffset { get; set; } = 0;
- public List Lines { get; } = new();
- public Point CursorPosition { get; } = new(0, 0);
- public Mode EditMode { get; set; } = Mode.Command;
- public string CurrentPath { get; set; } = string.Empty;
-
- public TextEditor(string path) : this()
+ if (File.Exists(path))
{
- if (File.Exists(path))
- {
- _ = Load(path);
- }
+ _ = Load(path);
+ }
+ }
+
+ public TextEditor()
+ {
+ YesNtInterpreter.Initialize();
+ YesNtInterpreter.OnDebugOutput += YesNtInterpreter_OnDebugOutput;
+ YesNtInterpreter.OnLineExecuted += YesNtInterpreter_OnLineExecuted;
+ syntaxHighlighter = new(YesNtInterpreter.StatementInformation);
+ inputHandler = new InputHandler(this);
+ Console.CancelKeyPress += Console_CancelKeyPress;
+ }
+
+ public void Run()
+ {
+ Console.Clear();
+
+ Display(true);
+ do
+ {
+ Display(false);
+ } while (inputHandler.HandleInput());
+
+ Console.Clear();
+ }
+
+ public void Display(bool drawAll)
+ {
+ Console.CursorVisible = false;
+ Console.ForegroundColor = ConsoleColor.Gray;
+ Console.BackgroundColor = ConsoleColor.Black;
+
+ Console.SetCursorPosition(0, 0);
+
+ if (SizeChanged())
+ {
+ drawAll = true;
+ InputHandler.WriteStatus(string.Empty);
}
- public TextEditor()
+ if (LineOffset < 0 || CursorPosition.Y < 0 || CursorPosition.Y < 0)
{
- YesNtInterpreter.Initialize();
- YesNtInterpreter.OnDebugOutput += YesNtInterpreter_OnDebugOutput;
- YesNtInterpreter.OnLineExecuted += YesNtInterpreter_OnLineExecuted;
- syntaxHighlighter = new(YesNtInterpreter.StatementInformation);
- inputHandler = new InputHandler(this);
- Console.CancelKeyPress += Console_CancelKeyPress;
+ LineOffset = 0;
+ CursorPosition.Y = 0;
+ CursorPosition.X = 0;
}
- public void Run()
+ for (int i = LineOffset; i < Console.WindowHeight + LineOffset - 2; i++)
{
- Console.Clear();
+ Console.SetCursorPosition(0, i - LineOffset);
- Display(true);
- do
+ string lineCountString = $"{i + 1}".PadRight(GetSpacing(), ' ') + "| ";
+ if (i < Lines.Count)
{
- Display(false);
- } while (inputHandler.HandleInput());
-
- Console.Clear();
- }
-
- public void Display(bool drawAll)
- {
- Console.CursorVisible = false;
- Console.ForegroundColor = ConsoleColor.Gray;
- Console.BackgroundColor = ConsoleColor.Black;
-
- Console.SetCursorPosition(0, 0);
-
- if (SizeChanged())
- {
- drawAll = true;
- InputHandler.WriteStatus(string.Empty);
- }
-
- if (LineOffset < 0 || CursorPosition.Y < 0 || CursorPosition.Y < 0)
- {
- LineOffset = 0;
- CursorPosition.Y = 0;
- CursorPosition.X = 0;
- }
-
- for (int i = LineOffset; i < Console.WindowHeight + LineOffset - 2; i++)
- {
- Console.SetCursorPosition(0, i - LineOffset);
-
- string lineCountString = $"{i + 1}".PadRight(GetSpacing(), ' ') + "| ";
- if (i < Lines.Count)
+ if (CursorPosition.Y == i || drawAll)
{
- if (CursorPosition.Y == i || drawAll)
- {
- Console.Write(lineCountString);
- string printLine = $"{Lines[i][..Math.Min(Lines[i].Length, Console.WindowWidth)]}".TrimEnd();
- syntaxHighlighter.Write(printLine);
- Console.Write(new string(' ', Math.Max(Console.WindowWidth - lineCountString.Length - printLine.Length, 0)));
- }
- }
- else if (drawAll || CursorPosition.Y == i)
- {
- Console.Write(lineCountString + new string(' ', Console.WindowWidth - lineCountString.Length));
+ Console.Write(lineCountString);
+ string printLine = $"{Lines[i][..Math.Min(Lines[i].Length, Console.WindowWidth)]}".TrimEnd();
+ syntaxHighlighter.Write(printLine);
+ Console.Write(new string(' ', Math.Max(Console.WindowWidth - lineCountString.Length - printLine.Length, 0)));
}
}
-
- Console.SetCursorPosition(0, Console.WindowHeight - 3);
- Console.Write(new string('-', Console.WindowWidth));
- Console.SetCursorPosition(0, Console.WindowHeight - 2);
- Console.Write(">>>" + new string(' ', Console.WindowWidth - 3));
-
- Console.SetCursorPosition(Math.Min(CursorPosition.X + GetSpacing() + 2, Console.WindowWidth - 1), CursorPosition.Y - LineOffset);
-
- Console.CursorVisible = true;
+ else if (drawAll || CursorPosition.Y == i)
+ {
+ Console.Write(lineCountString + new string(' ', Console.WindowWidth - lineCountString.Length));
+ }
}
- public bool Load(string path)
+ Console.SetCursorPosition(0, Console.WindowHeight - 3);
+ Console.Write(new string('-', Console.WindowWidth));
+ Console.SetCursorPosition(0, Console.WindowHeight - 2);
+ Console.Write(">>>" + new string(' ', Console.WindowWidth - 3));
+
+ Console.SetCursorPosition(Math.Min(CursorPosition.X + GetSpacing() + 2, Console.WindowWidth - 1), CursorPosition.Y - LineOffset);
+
+ Console.CursorVisible = true;
+ }
+
+ public bool Load(string path)
+ {
+ if (string.IsNullOrEmpty(Path.GetExtension(path)))
{
+ path = Path.ChangeExtension(path, "ynt");
+ }
+
+ if (!File.Exists(path))
+ {
+ InputHandler.WriteStatus("File does not exist!");
+ return false;
+ }
+
+ Lines.Clear();
+ Lines.AddRange(File.ReadAllLines(path));
+ CurrentPath = path;
+ InputHandler.WriteStatus("File Loaded!");
+ return true;
+ }
+
+ public bool Save(string input, bool loadIfExists)
+ {
+ string path;
+ if (input.Split(' ').Length == 2)
+ {
+ path = input.Split(' ')[1];
+
+ if (CurrentPath.Trim() != path.Trim() && loadIfExists)
+ {
+ return Load(path);
+ }
if (string.IsNullOrEmpty(Path.GetExtension(path)))
{
path = Path.ChangeExtension(path, "ynt");
}
-
- if (!File.Exists(path))
- {
- InputHandler.WriteStatus("File does not exist!");
- return false;
- }
-
- Lines.Clear();
- Lines.AddRange(File.ReadAllLines(path));
CurrentPath = path;
- InputHandler.WriteStatus("File Loaded!");
+ }
+ else if (!string.IsNullOrWhiteSpace(CurrentPath))
+ {
+ path = CurrentPath;
+ }
+ else if (input.Split(' ').Length > 2)
+ {
+ InputHandler.WriteStatus("Invalid arguments!");
+ return false;
+ }
+ else
+ {
+ InputHandler.WriteStatus("File path is empty! (Save the file before you can use this command)");
+ return false;
+ }
+
+ if (string.IsNullOrEmpty(Path.GetExtension(path)))
+ {
+ path = Path.ChangeExtension(path, "ynt");
+ }
+
+ while (Lines.Count > 0 && string.IsNullOrWhiteSpace(Lines[^1]))
+ {
+ Lines.RemoveAt(Lines.Count - 1);
+ }
+
+ try
+ {
+ File.WriteAllLines(path, Lines);
+ InputHandler.WriteStatus("File Saved!");
return true;
}
-
- public bool Save(string input, bool loadIfExists)
+ catch (Exception ex)
{
- string path;
- if (input.Split(' ').Length == 2)
- {
- path = input.Split(' ')[1];
-
- if (CurrentPath.Trim() != path.Trim() && loadIfExists)
- {
- return Load(path);
- }
- if (string.IsNullOrEmpty(Path.GetExtension(path)))
- {
- path = Path.ChangeExtension(path, "ynt");
- }
- CurrentPath = path;
- }
- else if (!string.IsNullOrWhiteSpace(CurrentPath))
- {
- path = CurrentPath;
- }
- else if (input.Split(' ').Length > 2)
- {
- InputHandler.WriteStatus("Invalid arguments!");
- return false;
- }
- else
- {
- InputHandler.WriteStatus("File path is empty! (Save the file before you can use this command)");
- return false;
- }
-
- if (string.IsNullOrEmpty(Path.GetExtension(path)))
- {
- path = Path.ChangeExtension(path, "ynt");
- }
-
- while (Lines.Count > 0 && string.IsNullOrWhiteSpace(Lines[^1]))
- {
- Lines.RemoveAt(Lines.Count - 1);
- }
-
- try
- {
- File.WriteAllLines(path, Lines);
- InputHandler.WriteStatus("File Saved!");
- return true;
- }
- catch (Exception ex)
- {
- InputHandler.WriteStatus(ex.Message);
- return false;
- }
- }
-
- private void YesNtInterpreter_OnDebugOutput(string output)
- {
- debugOutput.Add(output);
- }
-
- private void YesNtInterpreter_OnLineExecuted(Interpreter.Runtime.DebugEventArgs e)
- {
- lock (Console.Out)
- {
- if (e is not null)
- {
- Console.ForegroundColor = ConsoleColor.Magenta;
-
- string sharedString = (Console.CursorLeft != 0) ? Environment.NewLine : string.Empty;
- sharedString += (e.IsTask ? $"[Task: {e.TaskId}]" : string.Empty) + $"[{e.LineNumber}]";
-
- if (e.OriginalLine == e.CurrentLine)
- {
- Console.WriteLine($"{sharedString}[{e.CurrentLine}] ==>");
- }
- else
- {
- Console.WriteLine($"{sharedString}[{e.OriginalLine}] => [{e.CurrentLine}] ==>");
- }
- Console.ForegroundColor = ConsoleColor.Gray;
- }
- string[] outputs = debugOutput.ToArray();
- debugOutput.Clear();
-
- foreach (string output in outputs)
- {
- Console.Write(output);
- }
- }
- }
-
- private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
- {
- e.Cancel = true;
- switch (EditMode)
- {
- case Mode.Debug:
- YesNtInterpreter.Stop();
- EditMode = Mode.Command;
- break;
- }
- }
-
- public int GetSpacing()
- {
- int padding = (Console.WindowHeight + LineOffset - 3).ToString().Length;
- padding = Math.Max(padding, Lines.Count.ToString().Length);
- padding += 1;
- return padding;
- }
-
- private readonly Point oldSize = new Point(0, 0);
-
- private bool SizeChanged()
- {
- if (oldSize.X != Console.WindowWidth || oldSize.Y != Console.WindowHeight)
- {
- oldSize.X = Console.WindowWidth;
- oldSize.Y = Console.WindowHeight;
- return true;
- }
+ InputHandler.WriteStatus(ex.Message);
return false;
}
}
- internal class Point
+ public int GetSpacing()
{
- public int X { get; set; }
- public int Y { get; set; }
+ int padding = (Console.WindowHeight + LineOffset - 3).ToString().Length;
+ padding = Math.Max(padding, Lines.Count.ToString().Length);
+ padding += 1;
+ return padding;
+ }
- public Point(int x, int y)
+ private void YesNtInterpreter_OnDebugOutput(string output)
+ {
+ debugOutput.Add(output);
+ }
+
+ private void YesNtInterpreter_OnLineExecuted(Interpreter.Runtime.DebugEventArgs e)
+ {
+ lock (Console.Out)
{
- X = x;
- Y = y;
+ if (e is not null)
+ {
+ Console.ForegroundColor = ConsoleColor.Magenta;
+
+ string sharedString = (Console.CursorLeft != 0) ? Environment.NewLine : string.Empty;
+ sharedString += (e.IsTask ? $"[Task: {e.TaskId}]" : string.Empty) + $"[{e.LineNumber}]";
+
+ if (e.OriginalLine == e.CurrentLine)
+ {
+ Console.WriteLine($"{sharedString}[{e.CurrentLine}] ==>");
+ }
+ else
+ {
+ Console.WriteLine($"{sharedString}[{e.OriginalLine}] => [{e.CurrentLine}] ==>");
+ }
+ Console.ForegroundColor = ConsoleColor.Gray;
+ }
+ string[] outputs = debugOutput.ToArray();
+ debugOutput.Clear();
+
+ foreach (string output in outputs)
+ {
+ Console.Write(output);
+ }
}
}
- internal enum Mode
+ private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
- Edit,
- Command,
- Debug
+ e.Cancel = true;
+ switch (EditMode)
+ {
+ case Mode.Debug:
+ YesNtInterpreter.Stop();
+ EditMode = Mode.Command;
+ break;
+ }
}
+
+ private bool SizeChanged()
+ {
+ if (oldSize.X != Console.WindowWidth || oldSize.Y != Console.WindowHeight)
+ {
+ oldSize.X = Console.WindowWidth;
+ oldSize.Y = Console.WindowHeight;
+ return true;
+ }
+ return false;
+ }
+}
+
+internal class Point
+{
+ public int X { get; set; }
+ public int Y { get; set; }
+
+ public Point(int x, int y)
+ {
+ X = x;
+ Y = y;
+ }
+}
+
+internal enum Mode
+{
+ Edit,
+ Command,
+ Debug
}
\ No newline at end of file
diff --git a/YesNt.CodeEditor/InputHandler.cs b/YesNt.CodeEditor/InputHandler.cs
index 3b31f46..7a6f6b1 100644
--- a/YesNt.CodeEditor/InputHandler.cs
+++ b/YesNt.CodeEditor/InputHandler.cs
@@ -1,313 +1,317 @@
using System;
using System.Text;
-namespace YesNt.CodeEditor
+namespace YesNt.CodeEditor;
+
+internal class InputHandler
{
- internal class InputHandler
+ private readonly TextEditor textEditor;
+
+ public InputHandler(TextEditor textEditor)
{
- private readonly TextEditor textEditor;
+ this.textEditor = textEditor;
+ }
- public InputHandler(TextEditor textEditor)
+ public bool HandleInput()
+ {
+ while (Console.KeyAvailable)
{
- this.textEditor = textEditor;
+ _ = Console.ReadKey(true);
}
-
- public bool HandleInput()
+ if (textEditor.EditMode == Mode.Edit)
{
- while (Console.KeyAvailable)
- {
- _ = Console.ReadKey(true);
- }
- if (textEditor.EditMode == Mode.Edit)
- {
- ConsoleKeyInfo keyInfo = Console.ReadKey(true);
+ ConsoleKeyInfo keyInfo = Console.ReadKey(true);
- if ((ConsoleModifiers.Alt & keyInfo.Modifiers) == ConsoleModifiers.Alt)
+ if ((ConsoleModifiers.Alt & keyInfo.Modifiers) == ConsoleModifiers.Alt)
+ {
+ switch (keyInfo.Key)
{
- switch (keyInfo.Key)
- {
- case ConsoleKey.C:
- textEditor.EditMode = Mode.Command;
- return true;
+ case ConsoleKey.C:
+ textEditor.EditMode = Mode.Command;
+ return true;
- case ConsoleKey.B:
- int position = textEditor.Lines.Count;
- textEditor.CursorPosition.Y = position - 1;
- textEditor.LineOffset = Math.Max(position - Console.WindowHeight + 3, 0);
+ case ConsoleKey.B:
+ int position = textEditor.Lines.Count;
+ textEditor.CursorPosition.Y = position - 1;
+ textEditor.LineOffset = Math.Max(position - Console.WindowHeight + 3, 0);
- textEditor.Display(true);
- return true;
+ textEditor.Display(true);
+ return true;
- case ConsoleKey.T:
- textEditor.CursorPosition.Y = 0;
- textEditor.LineOffset = 0;
+ case ConsoleKey.T:
+ textEditor.CursorPosition.Y = 0;
+ textEditor.LineOffset = 0;
- textEditor.Display(true);
- return true;
+ textEditor.Display(true);
+ return true;
- case ConsoleKey.S:
- textEditor.CursorPosition.X = 0;
- return true;
+ case ConsoleKey.S:
+ textEditor.CursorPosition.X = 0;
+ return true;
- case ConsoleKey.E:
- textEditor.CursorPosition.X = textEditor.Lines.Count > textEditor.CursorPosition.Y ? textEditor.Lines[textEditor.CursorPosition.Y].TrimEnd().Length : 0;
- return true;
- }
+ case ConsoleKey.E:
+ textEditor.CursorPosition.X = textEditor.Lines.Count > textEditor.CursorPosition.Y ? textEditor.Lines[textEditor.CursorPosition.Y].TrimEnd().Length : 0;
+ return true;
}
- if (keyInfo.Key == ConsoleKey.DownArrow)
+ }
+ if (keyInfo.Key == ConsoleKey.DownArrow)
+ {
+ textEditor.CursorPosition.Y++;
+ if (textEditor.CursorPosition.Y - textEditor.LineOffset >= Console.WindowHeight - 3)
{
- textEditor.CursorPosition.Y++;
- if (textEditor.CursorPosition.Y - textEditor.LineOffset >= Console.WindowHeight - 3)
+ textEditor.LineOffset++;
+ textEditor.Display(true);
+ }
+ }
+ else if (keyInfo.Key == ConsoleKey.UpArrow)
+ {
+ if (textEditor.CursorPosition.Y > 0)
+ {
+ textEditor.CursorPosition.Y--;
+ if (textEditor.CursorPosition.Y - textEditor.LineOffset < 0 && textEditor.LineOffset > 0)
{
- textEditor.LineOffset++;
+ textEditor.LineOffset--;
textEditor.Display(true);
}
}
- else if (keyInfo.Key == ConsoleKey.UpArrow)
+ }
+ else if (keyInfo.Key == ConsoleKey.LeftArrow)
+ {
+ if (textEditor.CursorPosition.X > 0)
{
- if (textEditor.CursorPosition.Y > 0)
- {
- textEditor.CursorPosition.Y--;
- if (textEditor.CursorPosition.Y - textEditor.LineOffset < 0 && textEditor.LineOffset > 0)
- {
- textEditor.LineOffset--;
- textEditor.Display(true);
- }
- }
- }
- else if (keyInfo.Key == ConsoleKey.LeftArrow)
- {
- if (textEditor.CursorPosition.X > 0)
- {
- textEditor.CursorPosition.X--;
- }
- }
- else if (keyInfo.Key == ConsoleKey.RightArrow)
- {
- if (textEditor.CursorPosition.X + textEditor.GetSpacing() + 3 < Console.WindowWidth)
- {
- textEditor.CursorPosition.X++;
- }
- }
- else if (keyInfo.Key == ConsoleKey.Enter)
- {
- while (textEditor.Lines.Count <= textEditor.CursorPosition.Y)
- {
- textEditor.Lines.Add("");
- }
- textEditor.Lines.Insert(textEditor.CursorPosition.Y, "");
-
- string line = textEditor.Lines[textEditor.CursorPosition.Y + 1];
-
- textEditor.Lines[textEditor.CursorPosition.Y] = line[..Math.Min(textEditor.CursorPosition.X, line.Length)];
- textEditor.Lines[textEditor.CursorPosition.Y + 1] = line[Math.Min(textEditor.CursorPosition.X, line.Length)..];
-
- textEditor.CursorPosition.X = 0;
- textEditor.CursorPosition.Y++;
-
- if (textEditor.CursorPosition.Y - textEditor.LineOffset >= Console.WindowHeight - 3)
- {
- textEditor.LineOffset++;
- }
- textEditor.Display(true);
- }
- else
- {
- while (textEditor.Lines.Count <= textEditor.CursorPosition.Y)
- {
- textEditor.Lines.Add("");
- }
-
- StringBuilder lineBuilder = new StringBuilder(textEditor.Lines[textEditor.CursorPosition.Y]);
- while (lineBuilder.Length <= textEditor.CursorPosition.X)
- {
- _ = lineBuilder.Append(' ');
- }
-
- textEditor.Lines[textEditor.CursorPosition.Y] = lineBuilder.ToString();
-
- if (keyInfo.Key == ConsoleKey.Backspace)
- {
- if (textEditor.CursorPosition.X > 0)
- {
- if (textEditor.Lines[textEditor.CursorPosition.Y][textEditor.CursorPosition.X - 1] == ' ' && textEditor.CursorPosition.X > textEditor.Lines[textEditor.CursorPosition.Y].TrimEnd().Length)
- {
- textEditor.Lines[textEditor.CursorPosition.Y] = textEditor.Lines[textEditor.CursorPosition.Y].TrimEnd();
- textEditor.CursorPosition.X = textEditor.Lines[textEditor.CursorPosition.Y].Length;
- }
- else
- {
- textEditor.Lines[textEditor.CursorPosition.Y] = textEditor.Lines[textEditor.CursorPosition.Y].Remove(textEditor.CursorPosition.X - 1, 1);
- textEditor.CursorPosition.X--;
- }
- }
- else
- {
- if (textEditor.CursorPosition.Y > 0)
- {
- if (string.IsNullOrWhiteSpace(textEditor.Lines[textEditor.CursorPosition.Y - 1]))
- {
- textEditor.Lines.RemoveAt(--textEditor.CursorPosition.Y);
- }
- else
- {
- textEditor.CursorPosition.Y--;
- textEditor.CursorPosition.X = textEditor.Lines[textEditor.CursorPosition.Y].TrimEnd().Length;
- textEditor.Lines[textEditor.CursorPosition.Y] += textEditor.Lines[textEditor.CursorPosition.Y + 1];
- textEditor.Lines.RemoveAt(textEditor.CursorPosition.Y + 1);
- }
- if (textEditor.CursorPosition.Y - textEditor.LineOffset < 0 && textEditor.LineOffset > 0)
- {
- textEditor.LineOffset--;
- }
- textEditor.Display(true);
- }
- }
-
- while (textEditor.Lines.Count > 0 && string.IsNullOrWhiteSpace(textEditor.Lines[^1]))
- {
- textEditor.Lines.RemoveAt(textEditor.Lines.Count - 1);
- }
- }
- else if (textEditor.CursorPosition.X + textEditor.GetSpacing() + 3 < Console.WindowWidth)
- {
- char input = keyInfo.KeyChar;
- if (!char.IsControl(input))
- {
- textEditor.Lines[textEditor.CursorPosition.Y] = textEditor.Lines[textEditor.CursorPosition.Y].Insert(textEditor.CursorPosition.X, input.ToString());
- textEditor.CursorPosition.X++;
- }
- }
+ textEditor.CursorPosition.X--;
}
}
- else if (textEditor.EditMode == Mode.Command)
+ else if (keyInfo.Key == ConsoleKey.RightArrow)
{
- Console.SetCursorPosition(3, Console.WindowHeight - 2);
-
- string input = Console.ReadLine() ?? string.Empty;
- string command = input.Split(' ')[0].Trim();
- string path;
-
- Console.CursorVisible = false;
-
- switch (command)
+ if (textEditor.CursorPosition.X + textEditor.GetSpacing() + 3 < Console.WindowWidth)
{
- case "edit":
- WriteStatus(string.Empty);
- textEditor.EditMode = Mode.Edit;
- break;
+ textEditor.CursorPosition.X++;
+ }
+ }
+ else if (keyInfo.Key == ConsoleKey.Enter)
+ {
+ while (textEditor.Lines.Count <= textEditor.CursorPosition.Y)
+ {
+ textEditor.Lines.Add("");
+ }
+ textEditor.Lines.Insert(textEditor.CursorPosition.Y, "");
- case "line":
- WriteStatus(string.Empty);
+ string line = textEditor.Lines[textEditor.CursorPosition.Y + 1];
- bool success = false;
- int lineNumber = 0;
- if (input.Split(' ').Length == 2)
- {
- success = int.TryParse(input.Split(' ')[1], out lineNumber);
- }
+ textEditor.Lines[textEditor.CursorPosition.Y] = line[..Math.Min(textEditor.CursorPosition.X, line.Length)];
+ textEditor.Lines[textEditor.CursorPosition.Y + 1] = line[Math.Min(textEditor.CursorPosition.X, line.Length)..];
- if (success && lineNumber > 0)
- {
- textEditor.CursorPosition.Y = lineNumber - 1;
- textEditor.CursorPosition.X = 0;
- textEditor.LineOffset = lineNumber - 1;
- textEditor.EditMode = Mode.Edit;
- }
- else
- {
- WriteStatus("Invalid line number!");
- }
- break;
+ textEditor.CursorPosition.X = 0;
+ textEditor.CursorPosition.Y++;
- case "save":
- _ = textEditor.Save(input, false);
- break;
-
- case "run":
- if (textEditor.Save(input, true))
- {
- textEditor.EditMode = Mode.Debug;
- Console.Clear();
- Console.CursorVisible = true;
- textEditor.YesNtInterpreter.Execute(textEditor.CurrentPath);
- while (Console.KeyAvailable)
- {
- _ = Console.ReadKey(true);
- }
- _ = Console.ReadKey();
- WriteStatus(string.Empty);
- textEditor.EditMode = Mode.Command;
- }
- break;
-
- case "debug":
- if (textEditor.Save(input, true))
- {
- textEditor.EditMode = Mode.Debug;
- Console.Clear();
- Console.CursorVisible = true;
- textEditor.YesNtInterpreter.Execute(textEditor.CurrentPath, true);
- while (Console.KeyAvailable)
- {
- _ = Console.ReadKey(true);
- }
- _ = Console.ReadKey();
- WriteStatus(string.Empty);
- textEditor.EditMode = Mode.Command;
- }
- break;
-
- case "load":
- if (input.Split(' ').Length == 2)
- {
- path = input.Split(' ')[1];
- }
- else
- {
- WriteStatus("Invalid arguments!");
- break;
- }
-
- try
- {
- _ = textEditor.Load(path);
- }
- catch (Exception ex)
- {
- WriteStatus(ex.Message);
- }
- textEditor.LineOffset = 0;
- textEditor.CursorPosition.X = 0;
- textEditor.CursorPosition.Y = 0;
- break;
-
- case "new":
-
- textEditor.LineOffset = 0;
- textEditor.CursorPosition.X = 0;
- textEditor.CursorPosition.Y = 0;
- textEditor.CurrentPath = string.Empty;
- textEditor.Lines.Clear();
- WriteStatus(string.Empty);
- break;
-
- case "exit":
- return false;
-
- default:
- WriteStatus("Command not found!");
- break;
+ if (textEditor.CursorPosition.Y - textEditor.LineOffset >= Console.WindowHeight - 3)
+ {
+ textEditor.LineOffset++;
}
textEditor.Display(true);
}
- return true;
- }
+ else
+ {
+ while (textEditor.Lines.Count <= textEditor.CursorPosition.Y)
+ {
+ textEditor.Lines.Add("");
+ }
- internal static void WriteStatus(string input)
- {
- Console.SetCursorPosition(0, Console.WindowHeight - 1);
- Console.Write(input + new string(' ', Console.WindowWidth - input.Length - 1));
+ StringBuilder lineBuilder = new StringBuilder(textEditor.Lines[textEditor.CursorPosition.Y]);
+ while (lineBuilder.Length <= textEditor.CursorPosition.X)
+ {
+ _ = lineBuilder.Append(' ');
+ }
+
+ textEditor.Lines[textEditor.CursorPosition.Y] = lineBuilder.ToString();
+
+ if (keyInfo.Key is ConsoleKey.Backspace or ConsoleKey.Delete)
+ {
+ if (keyInfo.Key == ConsoleKey.Delete)
+ {
+ textEditor.CursorPosition.X++;
+ }
+
+ if (textEditor.CursorPosition.X > 0)
+ {
+ if (textEditor.Lines[textEditor.CursorPosition.Y][textEditor.CursorPosition.X - 1] == ' ' && textEditor.CursorPosition.X > textEditor.Lines[textEditor.CursorPosition.Y].TrimEnd().Length)
+ {
+ textEditor.Lines[textEditor.CursorPosition.Y] = textEditor.Lines[textEditor.CursorPosition.Y].TrimEnd();
+ textEditor.CursorPosition.X = textEditor.Lines[textEditor.CursorPosition.Y].Length;
+ }
+ else
+ {
+ textEditor.Lines[textEditor.CursorPosition.Y] = textEditor.Lines[textEditor.CursorPosition.Y].Remove(textEditor.CursorPosition.X - 1, 1);
+ textEditor.CursorPosition.X--;
+ }
+ }
+ else
+ {
+ if (textEditor.CursorPosition.Y > 0)
+ {
+ if (string.IsNullOrWhiteSpace(textEditor.Lines[textEditor.CursorPosition.Y - 1]))
+ {
+ textEditor.Lines.RemoveAt(--textEditor.CursorPosition.Y);
+ }
+ else
+ {
+ textEditor.CursorPosition.Y--;
+ textEditor.CursorPosition.X = textEditor.Lines[textEditor.CursorPosition.Y].TrimEnd().Length;
+ textEditor.Lines[textEditor.CursorPosition.Y] += textEditor.Lines[textEditor.CursorPosition.Y + 1];
+ textEditor.Lines.RemoveAt(textEditor.CursorPosition.Y + 1);
+ }
+ if (textEditor.CursorPosition.Y - textEditor.LineOffset < 0 && textEditor.LineOffset > 0)
+ {
+ textEditor.LineOffset--;
+ }
+ textEditor.Display(true);
+ }
+ }
+
+ while (textEditor.Lines.Count > 0 && string.IsNullOrWhiteSpace(textEditor.Lines[^1]))
+ {
+ textEditor.Lines.RemoveAt(textEditor.Lines.Count - 1);
+ }
+ }
+ else if (textEditor.CursorPosition.X + textEditor.GetSpacing() + 3 < Console.WindowWidth)
+ {
+ char input = keyInfo.KeyChar;
+ if (!char.IsControl(input))
+ {
+ textEditor.Lines[textEditor.CursorPosition.Y] = textEditor.Lines[textEditor.CursorPosition.Y].Insert(textEditor.CursorPosition.X, input.ToString());
+ textEditor.CursorPosition.X++;
+ }
+ }
+ }
}
+ else if (textEditor.EditMode == Mode.Command)
+ {
+ Console.SetCursorPosition(3, Console.WindowHeight - 2);
+
+ string input = Console.ReadLine() ?? string.Empty;
+ string command = input.Split(' ')[0].Trim();
+ string path;
+
+ Console.CursorVisible = false;
+
+ switch (command)
+ {
+ case "edit":
+ WriteStatus(string.Empty);
+ textEditor.EditMode = Mode.Edit;
+ break;
+
+ case "line":
+ WriteStatus(string.Empty);
+
+ bool success = false;
+ int lineNumber = 0;
+ if (input.Split(' ').Length == 2)
+ {
+ success = int.TryParse(input.Split(' ')[1], out lineNumber);
+ }
+
+ if (success && lineNumber > 0)
+ {
+ textEditor.CursorPosition.Y = lineNumber - 1;
+ textEditor.CursorPosition.X = 0;
+ textEditor.LineOffset = lineNumber - 1;
+ textEditor.EditMode = Mode.Edit;
+ }
+ else
+ {
+ WriteStatus("Invalid line number!");
+ }
+ break;
+
+ case "save":
+ _ = textEditor.Save(input, false);
+ break;
+
+ case "run":
+ if (textEditor.Save(input, true))
+ {
+ textEditor.EditMode = Mode.Debug;
+ Console.Clear();
+ Console.CursorVisible = true;
+ textEditor.YesNtInterpreter.Execute(textEditor.CurrentPath);
+ while (Console.KeyAvailable)
+ {
+ _ = Console.ReadKey(true);
+ }
+ _ = Console.ReadKey();
+ WriteStatus(string.Empty);
+ textEditor.EditMode = Mode.Command;
+ }
+ break;
+
+ case "debug":
+ if (textEditor.Save(input, true))
+ {
+ textEditor.EditMode = Mode.Debug;
+ Console.Clear();
+ Console.CursorVisible = true;
+ textEditor.YesNtInterpreter.Execute(textEditor.CurrentPath, true);
+ while (Console.KeyAvailable)
+ {
+ _ = Console.ReadKey(true);
+ }
+ _ = Console.ReadKey();
+ WriteStatus(string.Empty);
+ textEditor.EditMode = Mode.Command;
+ }
+ break;
+
+ case "load":
+ if (input.Split(' ').Length == 2)
+ {
+ path = input.Split(' ')[1];
+ }
+ else
+ {
+ WriteStatus("Invalid arguments!");
+ break;
+ }
+
+ try
+ {
+ _ = textEditor.Load(path);
+ }
+ catch (Exception ex)
+ {
+ WriteStatus(ex.Message);
+ }
+ textEditor.LineOffset = 0;
+ textEditor.CursorPosition.X = 0;
+ textEditor.CursorPosition.Y = 0;
+ break;
+
+ case "new":
+
+ textEditor.LineOffset = 0;
+ textEditor.CursorPosition.X = 0;
+ textEditor.CursorPosition.Y = 0;
+ textEditor.CurrentPath = string.Empty;
+ textEditor.Lines.Clear();
+ WriteStatus(string.Empty);
+ break;
+
+ case "exit":
+ return false;
+
+ default:
+ WriteStatus("Command not found!");
+ break;
+ }
+ textEditor.Display(true);
+ }
+ return true;
+ }
+
+ internal static void WriteStatus(string input)
+ {
+ Console.SetCursorPosition(0, Console.WindowHeight - 1);
+ Console.Write(input + new string(' ', Console.WindowWidth - input.Length - 1));
}
}
\ No newline at end of file
diff --git a/YesNt.CodeEditor/Program.cs b/YesNt.CodeEditor/Program.cs
index ffa8ec7..5b5517b 100644
--- a/YesNt.CodeEditor/Program.cs
+++ b/YesNt.CodeEditor/Program.cs
@@ -1,11 +1,4 @@
-namespace YesNt.CodeEditor
-{
- internal static class Program
- {
- private static void Main(string[] args)
- {
- TextEditor textEditor = args.Length > 0 ? new TextEditor(args[0]) : new TextEditor();
- textEditor.Run();
- }
- }
-}
\ No newline at end of file
+using YesNt.CodeEditor;
+
+TextEditor textEditor = args.Length > 0 ? new TextEditor(args[0]) : new TextEditor();
+textEditor.Run();
\ No newline at end of file
diff --git a/YesNt.CodeEditor/SyntaxHighlighter.cs b/YesNt.CodeEditor/SyntaxHighlighter.cs
index 7ef4d22..5e8a869 100644
--- a/YesNt.CodeEditor/SyntaxHighlighter.cs
+++ b/YesNt.CodeEditor/SyntaxHighlighter.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.ObjectModel;
+using System.Linq;
using System.Text.RegularExpressions;
using YesNt.Interpreter.Enums;
@@ -11,10 +12,12 @@ namespace YesNt.CodeEditor;
internal partial class SyntaxHighlighter
{
private readonly ReadOnlyCollection statementInformation;
+ private readonly string[] replacementValues;
public SyntaxHighlighter(ReadOnlyCollection statementInformation)
{
this.statementInformation = statementInformation;
+ replacementValues = StringExtentions.ReplacementRules.Values.ToArray();
}
public static string Base64Encode(string plainText)
@@ -39,10 +42,9 @@ internal partial class SyntaxHighlighter
}
else
{
- MatchCollection matches = EscapeSequenceRegex().Matches(input);
- for (int i = 0; i < matches.Count; i++)
+ for (int i = 0; i < replacementValues.Length; i++)
{
- input = AddColorInformation(input, matches[i].Value, ConsoleColor.DarkYellow, SearchMode.Contains);
+ input = AddColorInformation(input, replacementValues[i], ConsoleColor.Blue, SearchMode.Contains);
}
foreach (StatementInformation statement in statementInformation)
@@ -110,7 +112,7 @@ internal partial class SyntaxHighlighter
}
}
- matches = VariableRegex().Matches(input);
+ MatchCollection matches = VariableRegex().Matches(input);
for (int i = 0; i < matches.Count; i++)
{
input = AddColorInformation(input, matches[i].Value, ConsoleColor.Cyan, SearchMode.Contains);
@@ -171,9 +173,6 @@ internal partial class SyntaxHighlighter
return reult;
}
- [GeneratedRegex("!!.")]
- private static partial Regex EscapeSequenceRegex();
-
[GeneratedRegex("^<[a-zA-Z0-9]+")]
private static partial Regex VariableDeclarationRegex();
diff --git a/YesNt.Interpreter.Tests/CodeFowTests.cs b/YesNt.Interpreter.Tests/CodeFowTests.cs
index 23a715a..438116b 100644
--- a/YesNt.Interpreter.Tests/CodeFowTests.cs
+++ b/YesNt.Interpreter.Tests/CodeFowTests.cs
@@ -38,7 +38,6 @@ public class CodeFlowTests
[TestMethod]
public void CalculationsTest()
{
- Assert.Inconclusive();
- YesNtAssert.IsLineEqual("10 * 10 !calc", 20.ToString());
+ YesNtAssert.IsLineEqual("10 * 10 !calc", 100.ToString());
}
}
\ No newline at end of file
diff --git a/YesNt.Interpreter.Tests/YesNtAssert.cs b/YesNt.Interpreter.Tests/YesNtAssert.cs
index b7200a6..b3aa128 100644
--- a/YesNt.Interpreter.Tests/YesNtAssert.cs
+++ b/YesNt.Interpreter.Tests/YesNtAssert.cs
@@ -60,4 +60,26 @@ internal static class YesNtAssert
Assert.AreEqual(expected, debugEventArgs.CurrentLine);
}
+
+ public static void IsLineNotEqual(string line, string expected, int timeout = 1000)
+ {
+ AutoResetEvent onDone = new AutoResetEvent(false);
+ List lines = new List()
+ {
+ line
+ };
+
+ DebugEventArgs debugEventArgs = new DebugEventArgs();
+ yesNtInterpreter.OnLineExecuted += (er) =>
+ {
+ debugEventArgs = er ?? debugEventArgs;
+ _ = onDone.Set();
+ };
+
+ yesNtInterpreter.Execute(lines, true);
+
+ _ = onDone.WaitOne(TimeSpan.FromMilliseconds(timeout));
+
+ Assert.AreNotEqual(expected, debugEventArgs.CurrentLine);
+ }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Statements/ProcessingStatements.cs b/YesNt.Interpreter/Statements/ProcessingStatements.cs
index 0b5bd26..54cebf4 100644
--- a/YesNt.Interpreter/Statements/ProcessingStatements.cs
+++ b/YesNt.Interpreter/Statements/ProcessingStatements.cs
@@ -38,23 +38,6 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
RuntimeInfo.CurrentLine = args.FromSafeString();
}
- [Statement("!!", SearchMode.Contains, SpaceAround.None, ConsoleColor.DarkYellow, Priority = Priority.PreProcessing, KeepStatementInArgs = true)]
- public void DontEvaluate(string args)
- {
- int index;
- while ((index = args.IndexOf("!!")) != -1)
- {
- args = args.Remove(index, 2);
- if (index < args.Length)
- {
- char charToEscape = args[index];
- args = args.Remove(index, 1);
- args = args.Insert(index, charToEscape.ToString().ToSafeString());
- }
- }
- RuntimeInfo.CurrentLine = args;
- }
-
[Statement("!task", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.VeryHigh)]
public void RunTask(string line)
{
@@ -77,8 +60,14 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
[Statement("slp", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
public void Sleep(string args)
{
- _ = int.TryParse(args, out int millisecondsTimeout);
- ConsoleExtentions.Sleep(millisecondsTimeout, RuntimeInfo);
+ if (int.TryParse(args, out int millisecondsTimeout))
+ {
+ ConsoleExtentions.Sleep(millisecondsTimeout, RuntimeInfo);
+ }
+ else
+ {
+ RuntimeInfo.Exit($"\"{args}\" is not a valid time-out value", true);
+ }
}
[Statement("len", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
diff --git a/YesNt.Interpreter/Statements/VariableStatements.cs b/YesNt.Interpreter/Statements/VariableStatements.cs
index 490512d..5fd4c5d 100644
--- a/YesNt.Interpreter/Statements/VariableStatements.cs
+++ b/YesNt.Interpreter/Statements/VariableStatements.cs
@@ -91,6 +91,11 @@ internal partial class VariableStatements : StatementRuntimeInformation
MatchCollection matches = VariableStatementRegex().Matches(RuntimeInfo.CurrentLine);
+ if (matches.Count <= 0)
+ {
+ RuntimeInfo.Exit("Invalid syntax", true);
+ }
+
for (int i = 0; i < matches.Count; i++)
{
string varName = matches[i].Value.Replace(">", string.Empty);
diff --git a/YesNt.Interpreter/Utilities/StringExtentions.cs b/YesNt.Interpreter/Utilities/StringExtentions.cs
index 06efe5f..ca042b8 100644
--- a/YesNt.Interpreter/Utilities/StringExtentions.cs
+++ b/YesNt.Interpreter/Utilities/StringExtentions.cs
@@ -1,11 +1,34 @@
using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
+using System.Linq;
using System.Text;
namespace YesNt.Interpreter.Utilities;
public static class StringExtentions
{
+ private static readonly Dictionary reverseReplacementRules;
+
+ public static Dictionary ReplacementRules { get; } = new()
+ {
+ {"~", "~til" },
+ {" ", "~spc" },
+ {"%", "~per" },
+ {"<", "~let" },
+ {">", "~grt" },
+ {",", "~com" },
+ {"!", "~exm" },
+ {"|", "~pip" }
+ };
+
+ [SuppressMessage("Minor Code Smell", "S3963:\"static\" fields should be initialized inline", Justification = "Doesn't work because it throws a TypeInitializationException")]
+ static StringExtentions()
+ {
+ reverseReplacementRules = ReplacementRules.ToDictionary(x => x.Value, x => x.Key);
+ }
+
public static string ToSafeString(this string input)
{
StringBuilder output = new StringBuilder();
@@ -13,16 +36,32 @@ public static class StringExtentions
{
_ = output.Append($"\v{c}\v");
}
- return output
- .ToString()
- .Replace(' ', '~');
+
+ return ReplaceOnce(output.ToString(), ReplacementRules);
}
public static string FromSafeString(this string input)
{
- return input
- .Replace("\v", "")
- .Replace('~', ' ');
+ return ReplaceOnce(input.Replace("\v", ""), reverseReplacementRules);
+ }
+
+ public static string ReplaceOnce(string input, Dictionary replacementRules)
+ {
+ IEnumerable> matches = replacementRules.Where(rule => input.Contains(rule.Key));
+ if (!matches.Any())
+ {
+ return input;
+ }
+
+ KeyValuePair match = matches.First();
+ int startIndex = input.IndexOf(match.Key);
+ int endIndex = startIndex + match.Key.Length;
+
+ string before = ReplaceOnce(input[..startIndex], replacementRules);
+ string replaced = match.Value;
+ string after = ReplaceOnce(input[endIndex..], replacementRules);
+
+ return before + replaced + after;
}
public static bool ToStandardizedNumber(this string input, out double result)
From 1ac6d7790b03b527a8de05a8e72da2127737907c Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Thu, 28 Sep 2023 14:43:53 +0200
Subject: [PATCH 12/73] Automatically redraw console window when size chnages
---
YesNt.CodeEditor/Editor.cs | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/YesNt.CodeEditor/Editor.cs b/YesNt.CodeEditor/Editor.cs
index 7c8c08b..d88677b 100644
--- a/YesNt.CodeEditor/Editor.cs
+++ b/YesNt.CodeEditor/Editor.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Timers;
using YesNt.Interpreter.Runtime;
@@ -36,6 +37,22 @@ internal class TextEditor
syntaxHighlighter = new(YesNtInterpreter.StatementInformation);
inputHandler = new InputHandler(this);
Console.CancelKeyPress += Console_CancelKeyPress;
+
+ Timer timer = new Timer(500);
+ timer.Elapsed += (s, e) =>
+ {
+ if (SizeChanged() && EditMode != Mode.Debug)
+ {
+ Display(true);
+
+ if (EditMode == Mode.Command)
+ {
+ InputHandler.WriteStatus(string.Empty);
+ Console.SetCursorPosition(3, Console.WindowHeight - 2);
+ }
+ }
+ };
+ timer.Start();
}
public void Run()
From 84afe70c96a885d71cdc42c0bf1cf14e9cd24240 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Thu, 28 Sep 2023 16:27:36 +0200
Subject: [PATCH 13/73] Fix crash when resizing and cursor is off screen
---
YesNt.CodeEditor/Editor.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/YesNt.CodeEditor/Editor.cs b/YesNt.CodeEditor/Editor.cs
index d88677b..7637538 100644
--- a/YesNt.CodeEditor/Editor.cs
+++ b/YesNt.CodeEditor/Editor.cs
@@ -38,7 +38,7 @@ internal class TextEditor
inputHandler = new InputHandler(this);
Console.CancelKeyPress += Console_CancelKeyPress;
- Timer timer = new Timer(500);
+ Timer timer = new Timer(100);
timer.Elapsed += (s, e) =>
{
if (SizeChanged() && EditMode != Mode.Debug)
@@ -115,7 +115,7 @@ internal class TextEditor
Console.SetCursorPosition(0, Console.WindowHeight - 2);
Console.Write(">>>" + new string(' ', Console.WindowWidth - 3));
- Console.SetCursorPosition(Math.Min(CursorPosition.X + GetSpacing() + 2, Console.WindowWidth - 1), CursorPosition.Y - LineOffset);
+ Console.SetCursorPosition(Math.Min(CursorPosition.X + GetSpacing() + 2, Console.WindowWidth - 1), Math.Min(CursorPosition.Y - LineOffset, Console.WindowHeight - 4));
Console.CursorVisible = true;
}
From 7078ed5637e99057e24bc1eb72971b93202d95dc Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 7 Aug 2024 19:44:49 +0200
Subject: [PATCH 14/73] Upgrade to .NET 8 and code cleanup
---
.editorconfig | 3 +
YesNt.CodeEditor/Editor.cs | 16 +-
YesNt.CodeEditor/GlobalSuppressions.cs | 2 +-
YesNt.CodeEditor/InputHandler.cs | 9 +-
.../Properties/launchSettings.json | 18 +-
YesNt.CodeEditor/SyntaxHighlighter.cs | 40 +-
YesNt.CodeEditor/YesNt.CodeEditor.csproj | 2 +-
YesNt.Interpreter.Tests/CodeFowTests.cs | 12 +-
.../YesNt.Interpreter.Tests.csproj | 2 +-
YesNt.Interpreter.Tests/YesNtAssert.cs | 12 +-
.../Attributes/StatementAttribute.cs | 53 +-
.../Attributes/StaticStatementAttribute.cs | 13 +-
YesNt.Interpreter/Enums/Priority.cs | 21 +-
YesNt.Interpreter/Enums/SearchMode.cs | 15 +-
YesNt.Interpreter/Enums/SpaceAround.cs | 15 +-
YesNt.Interpreter/Program.cs | 25 +-
.../Properties/launchSettings.json | 20 +-
YesNt.Interpreter/Runtime/DebugEventArgs.cs | 17 +-
YesNt.Interpreter/Runtime/FunctionScope.cs | 16 +-
YesNt.Interpreter/Runtime/Line.cs | 22 +-
.../Runtime/RuntimeInformation.cs | 12 +-
.../Runtime/StatementInformation.cs | 19 +-
.../Runtime/StatementRuntimeInfo.cs | 9 +-
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 16 +-
.../Statements/CodeFlowStatements.cs | 361 ++++++-----
.../Statements/FunctionStatements.cs | 345 ++++++-----
.../PredifinedVariableStatements.cs | 99 ++-
.../Statements/ProcessingStatements.cs | 8 +-
.../Statements/SystemStatements.cs | 171 +++---
.../Statements/VariableStatements.cs | 12 +-
YesNt.Interpreter/Utilities/FixedProcess.cs | 577 +++++++++---------
.../Utilities/StringExtentions.cs | 4 +-
YesNt.Interpreter/YesNt.Interpreter.csproj | 2 +-
33 files changed, 960 insertions(+), 1008 deletions(-)
diff --git a/.editorconfig b/.editorconfig
index 0ec1ee4..4b19b40 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -114,3 +114,6 @@ dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+# IDE0305: Simplify collection initialization
+dotnet_diagnostic.IDE0305.severity = none
diff --git a/YesNt.CodeEditor/Editor.cs b/YesNt.CodeEditor/Editor.cs
index 7637538..11e1eb5 100644
--- a/YesNt.CodeEditor/Editor.cs
+++ b/YesNt.CodeEditor/Editor.cs
@@ -11,12 +11,12 @@ internal class TextEditor
{
private readonly InputHandler inputHandler;
private readonly SyntaxHighlighter syntaxHighlighter;
- private readonly List debugOutput = new();
+ private readonly List debugOutput = [];
private readonly Point oldSize = new Point(0, 0);
public YesNtInterpreter YesNtInterpreter { get; } = new();
public int LineOffset { get; set; } = 0;
- public List Lines { get; } = new();
+ public List Lines { get; } = [];
public Point CursorPosition { get; } = new(0, 0);
public Mode EditMode { get; set; } = Mode.Command;
public string CurrentPath { get; set; } = string.Empty;
@@ -263,16 +263,10 @@ internal class TextEditor
}
}
-internal class Point
+internal class Point(int x, int y)
{
- public int X { get; set; }
- public int Y { get; set; }
-
- public Point(int x, int y)
- {
- X = x;
- Y = y;
- }
+ public int X { get; set; } = x;
+ public int Y { get; set; } = y;
}
internal enum Mode
diff --git a/YesNt.CodeEditor/GlobalSuppressions.cs b/YesNt.CodeEditor/GlobalSuppressions.cs
index 3e5f094..05f5be2 100644
--- a/YesNt.CodeEditor/GlobalSuppressions.cs
+++ b/YesNt.CodeEditor/GlobalSuppressions.cs
@@ -5,4 +5,4 @@
using System.Diagnostics.CodeAnalysis;
-[assembly: SuppressMessage("Critical Code Smell", "S3998:Threads should not lock on objects with weak identity", Justification = "", Scope = "member", Target = "~M:YesNt.CodeEditor.TextEditor.YesNtInterpreter_OnLineExecuted(YesNt.Interpreter.Runtime.DebugEventArgs)")]
+[assembly: SuppressMessage("Critical Code Smell", "S3998:Threads should not lock on objects with weak identity", Justification = "", Scope = "member", Target = "~M:YesNt.CodeEditor.TextEditor.YesNtInterpreter_OnLineExecuted(YesNt.Interpreter.Runtime.DebugEventArgs)")]
\ No newline at end of file
diff --git a/YesNt.CodeEditor/InputHandler.cs b/YesNt.CodeEditor/InputHandler.cs
index 7a6f6b1..924e5b2 100644
--- a/YesNt.CodeEditor/InputHandler.cs
+++ b/YesNt.CodeEditor/InputHandler.cs
@@ -3,14 +3,9 @@ using System.Text;
namespace YesNt.CodeEditor;
-internal class InputHandler
+internal class InputHandler(TextEditor textEditor)
{
- private readonly TextEditor textEditor;
-
- public InputHandler(TextEditor textEditor)
- {
- this.textEditor = textEditor;
- }
+ private readonly TextEditor textEditor = textEditor;
public bool HandleInput()
{
diff --git a/YesNt.CodeEditor/Properties/launchSettings.json b/YesNt.CodeEditor/Properties/launchSettings.json
index 161eba8..d1da8c5 100644
--- a/YesNt.CodeEditor/Properties/launchSettings.json
+++ b/YesNt.CodeEditor/Properties/launchSettings.json
@@ -1,12 +1,12 @@
{
- "profiles": {
- "YesNt.CodeEditor": {
- "commandName": "Project"
- },
- "WSL": {
- "commandName": "WSL2",
- "environmentVariables": {},
- "distributionName": ""
+ "profiles": {
+ "YesNt.CodeEditor": {
+ "commandName": "Project"
+ },
+ "WSL": {
+ "commandName": "WSL2",
+ "environmentVariables": {},
+ "distributionName": ""
+ }
}
- }
}
\ No newline at end of file
diff --git a/YesNt.CodeEditor/SyntaxHighlighter.cs b/YesNt.CodeEditor/SyntaxHighlighter.cs
index 5e8a869..12c664e 100644
--- a/YesNt.CodeEditor/SyntaxHighlighter.cs
+++ b/YesNt.CodeEditor/SyntaxHighlighter.cs
@@ -9,16 +9,10 @@ using YesNt.Interpreter.Utilities;
namespace YesNt.CodeEditor;
-internal partial class SyntaxHighlighter
+internal partial class SyntaxHighlighter(ReadOnlyCollection statementInformation)
{
- private readonly ReadOnlyCollection statementInformation;
- private readonly string[] replacementValues;
-
- public SyntaxHighlighter(ReadOnlyCollection statementInformation)
- {
- this.statementInformation = statementInformation;
- replacementValues = StringExtentions.ReplacementRules.Values.ToArray();
- }
+ private readonly ReadOnlyCollection statementInformation = statementInformation;
+ private readonly string[] replacementValues = StringExtensions.ReplacementRules.Values.ToArray();
public static string Base64Encode(string plainText)
{
@@ -64,11 +58,11 @@ internal partial class SyntaxHighlighter
input = input.TrimEnd(' ');
if (statement.SearchMode == SearchMode.StartOfLine && input.StartsWith(name))
{
- if (statement.Seperator is not null && input.Contains(statement.Seperator))
+ if (statement.Separator is not null && input.Contains(statement.Separator))
{
- input = AddColorInformation(input, statement.Seperator, statement.Color, SearchMode.StartOfLine);
+ input = AddColorInformation(input, statement.Separator, statement.Color, SearchMode.StartOfLine);
}
- else if (statement.Seperator is not null)
+ else if (statement.Separator is not null)
{
continue;
}
@@ -76,11 +70,11 @@ internal partial class SyntaxHighlighter
}
else if (statement.SearchMode == SearchMode.Contains && input.Contains(name))
{
- if (statement.Seperator is not null && input.Contains(statement.Seperator))
+ if (statement.Separator is not null && input.Contains(statement.Separator))
{
- input = AddColorInformation(input, statement.Seperator, statement.Color, SearchMode.StartOfLine);
+ input = AddColorInformation(input, statement.Separator, statement.Color, SearchMode.StartOfLine);
}
- else if (statement.Seperator is not null)
+ else if (statement.Separator is not null)
{
continue;
}
@@ -88,11 +82,11 @@ internal partial class SyntaxHighlighter
}
else if (statement.SearchMode == SearchMode.EndOfLine && input.EndsWith(name))
{
- if (statement.Seperator is not null && input.Contains(statement.Seperator))
+ if (statement.Separator is not null && input.Contains(statement.Separator))
{
- input = AddColorInformation(input, statement.Seperator, statement.Color, SearchMode.StartOfLine);
+ input = AddColorInformation(input, statement.Separator, statement.Color, SearchMode.StartOfLine);
}
- else if (statement.Seperator is not null)
+ else if (statement.Separator is not null)
{
continue;
}
@@ -100,11 +94,11 @@ internal partial class SyntaxHighlighter
}
else if (statement.SearchMode == SearchMode.Exact && input.Equals(name))
{
- if (statement.Seperator is not null && input.Contains(statement.Seperator))
+ if (statement.Separator is not null && input.Contains(statement.Separator))
{
- input = AddColorInformation(input, statement.Seperator, statement.Color, SearchMode.StartOfLine);
+ input = AddColorInformation(input, statement.Separator, statement.Color, SearchMode.StartOfLine);
}
- else if (statement.Seperator is not null)
+ else if (statement.Separator is not null)
{
continue;
}
@@ -164,13 +158,13 @@ internal partial class SyntaxHighlighter
string base64Value = Base64Encode(value.TrimEnd());
- string reult = searchMode switch
+ string result = searchMode switch
{
SearchMode.StartOfLine => originalString.ReplaceFirstOccurrence(value, $"\0\r{(int)color}\r{base64Value}\0" + new string(' ', spacesAtEnd)),
SearchMode.EndOfLine => originalString.ReplaceLastOccurrence(value, $"\0\r{(int)color}\r{base64Value}\0" + new string(' ', spacesAtEnd)),
_ => originalString.Replace(value, $"\0\r{(int)color}\r{base64Value}\0" + new string(' ', spacesAtEnd))
};
- return reult;
+ return result;
}
[GeneratedRegex("^<[a-zA-Z0-9]+")]
diff --git a/YesNt.CodeEditor/YesNt.CodeEditor.csproj b/YesNt.CodeEditor/YesNt.CodeEditor.csproj
index dd3b5de..b7ba18b 100644
--- a/YesNt.CodeEditor/YesNt.CodeEditor.csproj
+++ b/YesNt.CodeEditor/YesNt.CodeEditor.csproj
@@ -2,7 +2,7 @@
Exe
- net7.0
+ net8.0
AnyCPU;x64
diff --git a/YesNt.Interpreter.Tests/CodeFowTests.cs b/YesNt.Interpreter.Tests/CodeFowTests.cs
index 438116b..66444e5 100644
--- a/YesNt.Interpreter.Tests/CodeFowTests.cs
+++ b/YesNt.Interpreter.Tests/CodeFowTests.cs
@@ -10,28 +10,28 @@ public class CodeFlowTests
[TestMethod]
public void FunctionTest()
{
- List lines = new List()
- {
+ List lines =
+ [
"cal yes",
"fnc yes",
"!result"
- };
+ ];
YesNtAssert.IsLastLineEqual(lines, "1");
}
[TestMethod]
public void LabelsTest()
{
- List lines = new List()
- {
+ List lines =
+ [
"result"
- };
+ ];
YesNtAssert.IsLastLineEqual(lines, "1");
}
diff --git a/YesNt.Interpreter.Tests/YesNt.Interpreter.Tests.csproj b/YesNt.Interpreter.Tests/YesNt.Interpreter.Tests.csproj
index 5172e5e..3090b90 100644
--- a/YesNt.Interpreter.Tests/YesNt.Interpreter.Tests.csproj
+++ b/YesNt.Interpreter.Tests/YesNt.Interpreter.Tests.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net8.0
enable
false
diff --git a/YesNt.Interpreter.Tests/YesNtAssert.cs b/YesNt.Interpreter.Tests/YesNtAssert.cs
index b3aa128..66638d9 100644
--- a/YesNt.Interpreter.Tests/YesNtAssert.cs
+++ b/YesNt.Interpreter.Tests/YesNtAssert.cs
@@ -42,10 +42,10 @@ internal static class YesNtAssert
public static void IsLineEqual(string line, string expected, int timeout = 1000)
{
AutoResetEvent onDone = new AutoResetEvent(false);
- List lines = new List()
- {
+ List lines =
+ [
line
- };
+ ];
DebugEventArgs debugEventArgs = new DebugEventArgs();
yesNtInterpreter.OnLineExecuted += (er) =>
@@ -64,10 +64,10 @@ internal static class YesNtAssert
public static void IsLineNotEqual(string line, string expected, int timeout = 1000)
{
AutoResetEvent onDone = new AutoResetEvent(false);
- List lines = new List()
- {
+ List lines =
+ [
line
- };
+ ];
DebugEventArgs debugEventArgs = new DebugEventArgs();
yesNtInterpreter.OnLineExecuted += (er) =>
diff --git a/YesNt.Interpreter/Attributes/StatementAttribute.cs b/YesNt.Interpreter/Attributes/StatementAttribute.cs
index 9b55c9b..999c9e8 100644
--- a/YesNt.Interpreter/Attributes/StatementAttribute.cs
+++ b/YesNt.Interpreter/Attributes/StatementAttribute.cs
@@ -2,35 +2,34 @@
using YesNt.Interpreter.Enums;
-namespace YesNt.Interpreter.Attributes
+namespace YesNt.Interpreter.Attributes;
+
+[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
+internal class StatementAttribute : Attribute
{
- [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
- internal class StatementAttribute : Attribute
+ public string Name { get; }
+ public SearchMode SearchMode { get; }
+ public SpaceAround SpaceAround { get; }
+ public ConsoleColor Color { get; set; }
+ public Priority Priority { get; set; } = Priority.Normal;
+ public bool ExecuteInSearchMode { get; set; }
+ public bool KeepStatementInArgs { get; set; }
+ public bool IgnoreSyntaxHighlighting { get; }
+ public string Separator { get; set; }
+
+ internal StatementAttribute(string name, SearchMode searchMode, SpaceAround spaceAround, ConsoleColor color)
{
- public string Name { get; }
- public SearchMode SearchMode { get; }
- public SpaceAround SpaceAround { get; }
- public ConsoleColor Color { get; set; }
- public Priority Priority { get; set; } = Priority.Normal;
- public bool ExecuteInSearchMode { get; set; }
- public bool KeepStatementInArgs { get; set; }
- public bool IgnoreSyntaxHighlighting { get; }
- public string Seperator { get; set; }
+ Name = name;
+ SearchMode = searchMode;
+ SpaceAround = spaceAround;
+ Color = color;
+ }
- internal StatementAttribute(string name, SearchMode searchMode, SpaceAround spaceAround, ConsoleColor color)
- {
- Name = name;
- SearchMode = searchMode;
- SpaceAround = spaceAround;
- Color = color;
- }
-
- internal StatementAttribute(string name, SearchMode searchMode, SpaceAround spaceAround)
- {
- Name = name;
- SearchMode = searchMode;
- SpaceAround = spaceAround;
- IgnoreSyntaxHighlighting = true;
- }
+ internal StatementAttribute(string name, SearchMode searchMode, SpaceAround spaceAround)
+ {
+ Name = name;
+ SearchMode = searchMode;
+ SpaceAround = spaceAround;
+ IgnoreSyntaxHighlighting = true;
}
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Attributes/StaticStatementAttribute.cs b/YesNt.Interpreter/Attributes/StaticStatementAttribute.cs
index 28bf029..f0c5a5a 100644
--- a/YesNt.Interpreter/Attributes/StaticStatementAttribute.cs
+++ b/YesNt.Interpreter/Attributes/StaticStatementAttribute.cs
@@ -2,12 +2,11 @@
using YesNt.Interpreter.Enums;
-namespace YesNt.Interpreter.Attributes
+namespace YesNt.Interpreter.Attributes;
+
+[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
+internal class StaticStatementAttribute : Attribute
{
- [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
- internal class StaticStatementAttribute : Attribute
- {
- public bool ExecuteInSearchMode { get; set; }
- public Priority Priority { get; set; } = Priority.Normal;
- }
+ public bool ExecuteInSearchMode { get; set; }
+ public Priority Priority { get; set; } = Priority.Normal;
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Enums/Priority.cs b/YesNt.Interpreter/Enums/Priority.cs
index a65051a..acb372b 100644
--- a/YesNt.Interpreter/Enums/Priority.cs
+++ b/YesNt.Interpreter/Enums/Priority.cs
@@ -1,13 +1,12 @@
-namespace YesNt.Interpreter.Enums
+namespace YesNt.Interpreter.Enums;
+
+internal enum Priority
{
- internal enum Priority
- {
- PreProcessing,
- Highest,
- VeryHigh,
- High,
- Normal,
- Low,
- VeryLow
- }
+ PreProcessing,
+ Highest,
+ VeryHigh,
+ High,
+ Normal,
+ Low,
+ VeryLow
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Enums/SearchMode.cs b/YesNt.Interpreter/Enums/SearchMode.cs
index 0e083b8..0226142 100644
--- a/YesNt.Interpreter/Enums/SearchMode.cs
+++ b/YesNt.Interpreter/Enums/SearchMode.cs
@@ -1,10 +1,9 @@
-namespace YesNt.Interpreter.Enums
+namespace YesNt.Interpreter.Enums;
+
+public enum SearchMode
{
- public enum SearchMode
- {
- StartOfLine,
- EndOfLine,
- Contains,
- Exact
- }
+ StartOfLine,
+ EndOfLine,
+ Contains,
+ Exact
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Enums/SpaceAround.cs b/YesNt.Interpreter/Enums/SpaceAround.cs
index c16fd85..0ee0990 100644
--- a/YesNt.Interpreter/Enums/SpaceAround.cs
+++ b/YesNt.Interpreter/Enums/SpaceAround.cs
@@ -1,10 +1,9 @@
-namespace YesNt.Interpreter.Enums
+namespace YesNt.Interpreter.Enums;
+
+public enum SpaceAround
{
- public enum SpaceAround
- {
- StartEnd,
- Start,
- End,
- None
- }
+ StartEnd,
+ Start,
+ End,
+ None
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Program.cs b/YesNt.Interpreter/Program.cs
index 70ce45e..ccbba14 100644
--- a/YesNt.Interpreter/Program.cs
+++ b/YesNt.Interpreter/Program.cs
@@ -2,22 +2,13 @@
using YesNt.Interpreter.Runtime;
-namespace YesNt.Interpreter
+if (args.Length == 1)
{
- internal static class Program
- {
- private static void Main(string[] args)
- {
- if (args.Length == 1)
- {
- YesNtInterpreter interpreter = new YesNtInterpreter();
- interpreter.Initialize();
- interpreter.Execute(args[0]);
- }
- else
- {
- Console.WriteLine("No path specified!");
- }
- }
- }
+ YesNtInterpreter interpreter = new YesNtInterpreter();
+ interpreter.Initialize();
+ interpreter.Execute(args[0]);
+}
+else
+{
+ Console.WriteLine("No path specified!");
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Properties/launchSettings.json b/YesNt.Interpreter/Properties/launchSettings.json
index f380490..60b7039 100644
--- a/YesNt.Interpreter/Properties/launchSettings.json
+++ b/YesNt.Interpreter/Properties/launchSettings.json
@@ -1,13 +1,13 @@
{
- "profiles": {
- "YesNt-Interpreter": {
- "commandName": "Project",
- "commandLineArgs": "code.ynt"
- },
- "WSL": {
- "commandName": "WSL2",
- "environmentVariables": {},
- "distributionName": ""
+ "profiles": {
+ "YesNt-Interpreter": {
+ "commandName": "Project",
+ "commandLineArgs": "code.ynt"
+ },
+ "WSL": {
+ "commandName": "WSL2",
+ "environmentVariables": {},
+ "distributionName": ""
+ }
}
- }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Runtime/DebugEventArgs.cs b/YesNt.Interpreter/Runtime/DebugEventArgs.cs
index 798d860..0f2d2fe 100644
--- a/YesNt.Interpreter/Runtime/DebugEventArgs.cs
+++ b/YesNt.Interpreter/Runtime/DebugEventArgs.cs
@@ -1,13 +1,12 @@
using System;
-namespace YesNt.Interpreter.Runtime
+namespace YesNt.Interpreter.Runtime;
+
+public class DebugEventArgs : EventArgs
{
- public class DebugEventArgs : EventArgs
- {
- public int LineNumber { get; internal set; }
- public string CurrentLine { get; internal set; }
- public string OriginalLine { get; internal set; }
- public int TaskId { get; internal set; }
- public bool IsTask { get; internal set; }
- }
+ public int LineNumber { get; internal set; }
+ public string CurrentLine { get; internal set; }
+ public string OriginalLine { get; internal set; }
+ public int TaskId { get; internal set; }
+ public bool IsTask { get; internal set; }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Runtime/FunctionScope.cs b/YesNt.Interpreter/Runtime/FunctionScope.cs
index 9b58e0c..cbae505 100644
--- a/YesNt.Interpreter/Runtime/FunctionScope.cs
+++ b/YesNt.Interpreter/Runtime/FunctionScope.cs
@@ -2,17 +2,11 @@
namespace YesNt.Interpreter.Runtime;
-internal class FunctionScope
+internal class FunctionScope(int callerLine, Stack arguments)
{
- public int CallerLine { get; }
- public Dictionary Variables { get; } = new();
- public Dictionary Labels { get; } = new();
- public Stack Arguemtns { get; }
+ public int CallerLine { get; } = callerLine;
+ public Dictionary Variables { get; } = [];
+ public Dictionary Labels { get; } = [];
+ public Stack Arguments { get; } = arguments;
public Stack Results { get; } = new();
-
- public FunctionScope(int callerLine, Stack arguemtns)
- {
- CallerLine = callerLine;
- Arguemtns = arguemtns;
- }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Runtime/Line.cs b/YesNt.Interpreter/Runtime/Line.cs
index 4243dac..7f3447d 100644
--- a/YesNt.Interpreter/Runtime/Line.cs
+++ b/YesNt.Interpreter/Runtime/Line.cs
@@ -1,16 +1,10 @@
-namespace YesNt.Interpreter.Runtime
-{
- internal class Line
- {
- public Line(string content, string fileName, int lineNumber)
- {
- Content = content;
- FileName = fileName;
- LineNumber = lineNumber;
- }
+namespace YesNt.Interpreter.Runtime;
- public string Content { get; set; }
- public string FileName { get; set; }
- public int LineNumber { get; set; }
- }
+internal class Line(string content, string fileName, int lineNumber)
+{
+ public string Content { get; set; } = content;
+
+ public string FileName { get; set; } = fileName;
+
+ public int LineNumber { get; set; } = lineNumber;
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Runtime/RuntimeInformation.cs b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
index c04e697..0eb4676 100644
--- a/YesNt.Interpreter/Runtime/RuntimeInformation.cs
+++ b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
@@ -14,16 +14,16 @@ internal sealed class RuntimeInformation
private event Action OnExit;
private static int internalTaskId = 0;
- private readonly Dictionary topVariables = new();
- private readonly Dictionary topLabels = new();
+ private readonly Dictionary topVariables = [];
+ private readonly Dictionary topLabels = [];
private RuntimeInformation parentRuntimeInformation;
private int taskId = 0;
- public Dictionary GloablVariables { get; set; } = new();
- public Dictionary Functions { get; } = new();
+ public Dictionary GlobalVariables { get; set; } = [];
+ public Dictionary Functions { get; } = [];
public Stack FunctionCallStack { get; } = new();
public Stack InParametersStack { get; } = new();
public Stack OutParametersStack { get; set; } = new();
- public List Lines { get; set; } = new();
+ public List Lines { get; set; } = [];
public string CurrentLine { get; set; } = string.Empty;
public string SearchLabel { get; set; } = string.Empty;
public string SearchFunction { get; set; } = string.Empty;
@@ -149,7 +149,7 @@ internal sealed class RuntimeInformation
{
topVariables.Clear();
Lines.Clear();
- GloablVariables.Clear();
+ GlobalVariables.Clear();
Labels.Clear();
Functions.Clear();
FunctionCallStack.Clear();
diff --git a/YesNt.Interpreter/Runtime/StatementInformation.cs b/YesNt.Interpreter/Runtime/StatementInformation.cs
index ed9489c..ab7e9a0 100644
--- a/YesNt.Interpreter/Runtime/StatementInformation.cs
+++ b/YesNt.Interpreter/Runtime/StatementInformation.cs
@@ -2,15 +2,14 @@
using YesNt.Interpreter.Enums;
-namespace YesNt.Interpreter.Runtime
+namespace YesNt.Interpreter.Runtime;
+
+public class StatementInformation
{
- public class StatementInformation
- {
- public string Name { get; internal set; }
- public SearchMode SearchMode { get; internal set; }
- public SpaceAround SpaceAround { get; internal set; }
- public ConsoleColor Color { get; internal set; }
- public bool IgnoreSyntaxHighlighting { get; internal set; }
- public string Seperator { get; set; }
- }
+ public string Name { get; internal set; }
+ public SearchMode SearchMode { get; internal set; }
+ public SpaceAround SpaceAround { get; internal set; }
+ public ConsoleColor Color { get; internal set; }
+ public bool IgnoreSyntaxHighlighting { get; internal set; }
+ public string Separator { get; set; }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Runtime/StatementRuntimeInfo.cs b/YesNt.Interpreter/Runtime/StatementRuntimeInfo.cs
index a0aaf2f..3a0c30a 100644
--- a/YesNt.Interpreter/Runtime/StatementRuntimeInfo.cs
+++ b/YesNt.Interpreter/Runtime/StatementRuntimeInfo.cs
@@ -1,7 +1,6 @@
-namespace YesNt.Interpreter.Runtime
+namespace YesNt.Interpreter.Runtime;
+
+internal abstract class StatementRuntimeInformation
{
- internal abstract class StatementRuntimeInformation
- {
- public RuntimeInformation RuntimeInfo { get; set; }
- }
+ public RuntimeInformation RuntimeInfo { get; set; }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index d11659a..fdfd80d 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -18,14 +18,14 @@ public class YesNtInterpreter
public event Action OnDebugOutput;
private readonly RuntimeInformation runtimeInfo = new RuntimeInformation();
- private Dictionary> statements = new();
- private List> staticStatements = new();
+ private Dictionary> statements = [];
+ private List> staticStatements = [];
public ReadOnlyCollection StatementInformation
{
get
{
- List informations = statements.Select(s =>
+ List information = statements.Select(s =>
{
return new StatementInformation()
{
@@ -34,11 +34,11 @@ public class YesNtInterpreter
SpaceAround = s.Key.SpaceAround,
Color = s.Key.Color,
IgnoreSyntaxHighlighting = s.Key.IgnoreSyntaxHighlighting,
- Seperator = s.Key.Seperator
+ Separator = s.Key.Separator
};
}).ToList();
- return new ReadOnlyCollection(informations);
+ return new ReadOnlyCollection(information);
}
}
@@ -118,14 +118,14 @@ public class YesNtInterpreter
Execute();
}
- internal void Execute(List lines, Dictionary gloablVariables, int startLine, RuntimeInformation parentRuntimeInformation)
+ internal void Execute(List lines, Dictionary globalVariables, int startLine, RuntimeInformation parentRuntimeInformation)
{
runtimeInfo.Reset();
runtimeInfo.IsDebugMode = parentRuntimeInformation.IsDebugMode;
runtimeInfo.Lines = lines;
runtimeInfo.LineNumber = startLine;
runtimeInfo.ParentRuntimeInformation = parentRuntimeInformation;
- runtimeInfo.GloablVariables = gloablVariables;
+ runtimeInfo.GlobalVariables = globalVariables;
if (parentRuntimeInformation.StopAllTasks)
{
runtimeInfo.Exit($"Parent task was terminated!", parentRuntimeInformation.StopAllTasks);
@@ -195,7 +195,7 @@ public class YesNtInterpreter
_ => statementAttribute.Name.Trim()
};
- if (statementAttribute.Seperator is null || runtimeInfo.CurrentLine.Contains(statementAttribute.Seperator))
+ if (statementAttribute.Separator is null || runtimeInfo.CurrentLine.Contains(statementAttribute.Separator))
{
if (statementAttribute.SearchMode == SearchMode.StartOfLine && runtimeInfo.CurrentLine.StartsWith(name))
{
diff --git a/YesNt.Interpreter/Statements/CodeFlowStatements.cs b/YesNt.Interpreter/Statements/CodeFlowStatements.cs
index 61bafcf..d1ccdd6 100644
--- a/YesNt.Interpreter/Statements/CodeFlowStatements.cs
+++ b/YesNt.Interpreter/Statements/CodeFlowStatements.cs
@@ -7,192 +7,191 @@ using YesNt.Interpreter.Enums;
using YesNt.Interpreter.Runtime;
using YesNt.Interpreter.Utilities;
-namespace YesNt.Interpreter.Statements
+namespace YesNt.Interpreter.Statements;
+
+internal class CodeFlowStatements : StatementRuntimeInformation
{
- internal class CodeFlowStatements : StatementRuntimeInformation
+ [Statement("jmp", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow)]
+ public void Jump(string args)
{
- [Statement("jmp", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow)]
- public void Jump(string args)
- {
- string key = args.Trim();
+ string key = args.Trim();
- if (RuntimeInfo.Labels.ContainsKey(key))
- {
- RuntimeInfo.LineNumber = RuntimeInfo.Labels[key];
- }
- else
- {
- RuntimeInfo.SearchLabel = key;
- RuntimeInfo.IsLocalSearch = RuntimeInfo.IsInFunction;
- }
+ if (RuntimeInfo.Labels.TryGetValue(key, out int value))
+ {
+ RuntimeInfo.LineNumber = value;
}
-
- [Statement("jif", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow, Seperator = "|")]
- public void JumpIf(string args)
+ else
{
- 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 is null)
- {
- RuntimeInfo.Exit("Invalid operation", true);
- return;
- }
-
- if (result == false)
- {
- return;
- }
-
- if (RuntimeInfo.Labels.ContainsKey(key))
- {
- RuntimeInfo.LineNumber = RuntimeInfo.Labels[key];
- }
- else
- {
- RuntimeInfo.SearchLabel = key;
- RuntimeInfo.IsLocalSearch = RuntimeInfo.IsInFunction;
- }
- }
-
- [Statement("lbl", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, ExecuteInSearchMode = 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;
- RuntimeInfo.IsLocalSearch = false;
- }
- }
-
- [Statement("cal", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, Priority = Priority.VeryLow)]
- public void Call(string args)
- {
- string key = args.Trim();
-
- RuntimeInfo.FunctionCallStack.Push(new FunctionScope(RuntimeInfo.LineNumber, new Stack(RuntimeInfo.InParametersStack.Reverse())));
- RuntimeInfo.InParametersStack.Clear();
-
- if (RuntimeInfo.Functions.ContainsKey(key))
- {
- RuntimeInfo.LineNumber = RuntimeInfo.Functions[key];
- }
- else
- {
- RuntimeInfo.SearchFunction = key;
- }
- }
-
- [Statement("cif", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, Priority = Priority.VeryLow, Seperator = "|")]
- public void CallIf(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 is null)
- {
- RuntimeInfo.Exit("Invalid operation", true);
- return;
- }
-
- if (result == false)
- {
- return;
- }
-
- RuntimeInfo.FunctionCallStack.Push(new FunctionScope(RuntimeInfo.LineNumber, new Stack(RuntimeInfo.InParametersStack)));
- RuntimeInfo.InParametersStack.Clear();
-
- if (RuntimeInfo.Functions.ContainsKey(key))
- {
- RuntimeInfo.LineNumber = RuntimeInfo.Functions[key];
- }
- else
- {
- RuntimeInfo.SearchFunction = key;
- }
- }
-
- [Statement("end", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red, ExecuteInSearchMode = true)]
- public void End(string _)
- {
- if (RuntimeInfo.IsSearching)
- {
- RuntimeInfo.IsInFunction = false;
- if (RuntimeInfo.IsLocalSearch)
- {
- RuntimeInfo.Exit($"Label \"{RuntimeInfo.SearchLabel}\" not found", true);
- }
-
- return;
- }
- else
- {
- RuntimeInfo.IsInFunction = false;
- }
-
- RuntimeInfo.Exit("Planned termination by code", false);
- }
-
- [Statement("trm", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red, ExecuteInSearchMode = true)]
- public void Terminate(string _)
- {
- if (RuntimeInfo.IsSearching)
- {
- RuntimeInfo.IsInFunction = false;
- if (RuntimeInfo.IsLocalSearch)
- {
- RuntimeInfo.Exit($"Label \"{RuntimeInfo.SearchLabel}\" not found", true);
- }
-
- return;
- }
- else
- {
- RuntimeInfo.IsInFunction = false;
- }
-
- RuntimeInfo.Exit("Planned termination by code. Canceling all tasks", true);
- }
-
- [Statement("trw", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Red)]
- public void Throw(string message)
- {
- RuntimeInfo.Exit(message, true);
- }
-
- [Statement("err", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Red)]
- public void Error(string message)
- {
- RuntimeInfo.Exit(message, false);
+ RuntimeInfo.SearchLabel = key;
+ RuntimeInfo.IsLocalSearch = RuntimeInfo.IsInFunction;
}
}
+
+ [Statement("jif", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow, Separator = "|")]
+ 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 is null)
+ {
+ RuntimeInfo.Exit("Invalid operation", true);
+ return;
+ }
+
+ if (result == false)
+ {
+ return;
+ }
+
+ if (RuntimeInfo.Labels.TryGetValue(key, out int value))
+ {
+ RuntimeInfo.LineNumber = value;
+ }
+ else
+ {
+ RuntimeInfo.SearchLabel = key;
+ RuntimeInfo.IsLocalSearch = RuntimeInfo.IsInFunction;
+ }
+ }
+
+ [Statement("lbl", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, ExecuteInSearchMode = 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;
+ RuntimeInfo.IsLocalSearch = false;
+ }
+ }
+
+ [Statement("cal", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, Priority = Priority.VeryLow)]
+ public void Call(string args)
+ {
+ string key = args.Trim();
+
+ RuntimeInfo.FunctionCallStack.Push(new FunctionScope(RuntimeInfo.LineNumber, new Stack(RuntimeInfo.InParametersStack.Reverse())));
+ RuntimeInfo.InParametersStack.Clear();
+
+ if (RuntimeInfo.Functions.TryGetValue(key, out int value))
+ {
+ RuntimeInfo.LineNumber = value;
+ }
+ else
+ {
+ RuntimeInfo.SearchFunction = key;
+ }
+ }
+
+ [Statement("cif", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, Priority = Priority.VeryLow, Separator = "|")]
+ public void CallIf(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 is null)
+ {
+ RuntimeInfo.Exit("Invalid operation", true);
+ return;
+ }
+
+ if (result == false)
+ {
+ return;
+ }
+
+ RuntimeInfo.FunctionCallStack.Push(new FunctionScope(RuntimeInfo.LineNumber, new Stack(RuntimeInfo.InParametersStack)));
+ RuntimeInfo.InParametersStack.Clear();
+
+ if (RuntimeInfo.Functions.TryGetValue(key, out int value))
+ {
+ RuntimeInfo.LineNumber = value;
+ }
+ else
+ {
+ RuntimeInfo.SearchFunction = key;
+ }
+ }
+
+ [Statement("end", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red, ExecuteInSearchMode = true)]
+ public void End(string _)
+ {
+ if (RuntimeInfo.IsSearching)
+ {
+ RuntimeInfo.IsInFunction = false;
+ if (RuntimeInfo.IsLocalSearch)
+ {
+ RuntimeInfo.Exit($"Label \"{RuntimeInfo.SearchLabel}\" not found", true);
+ }
+
+ return;
+ }
+ else
+ {
+ RuntimeInfo.IsInFunction = false;
+ }
+
+ RuntimeInfo.Exit("Planned termination by code", false);
+ }
+
+ [Statement("trm", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red, ExecuteInSearchMode = true)]
+ public void Terminate(string _)
+ {
+ if (RuntimeInfo.IsSearching)
+ {
+ RuntimeInfo.IsInFunction = false;
+ if (RuntimeInfo.IsLocalSearch)
+ {
+ RuntimeInfo.Exit($"Label \"{RuntimeInfo.SearchLabel}\" not found", true);
+ }
+
+ return;
+ }
+ else
+ {
+ RuntimeInfo.IsInFunction = false;
+ }
+
+ RuntimeInfo.Exit("Planned termination by code. Canceling all tasks", true);
+ }
+
+ [Statement("trw", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Red)]
+ public void Throw(string message)
+ {
+ RuntimeInfo.Exit(message, true);
+ }
+
+ [Statement("err", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Red)]
+ public void Error(string message)
+ {
+ RuntimeInfo.Exit(message, false);
+ }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Statements/FunctionStatements.cs b/YesNt.Interpreter/Statements/FunctionStatements.cs
index 23d67a6..de923c2 100644
--- a/YesNt.Interpreter/Statements/FunctionStatements.cs
+++ b/YesNt.Interpreter/Statements/FunctionStatements.cs
@@ -5,196 +5,195 @@ using YesNt.Interpreter.Attributes;
using YesNt.Interpreter.Enums;
using YesNt.Interpreter.Runtime;
-namespace YesNt.Interpreter.Statements
+namespace YesNt.Interpreter.Statements;
+
+internal class FunctionStatements : StatementRuntimeInformation
{
- internal class FunctionStatements : StatementRuntimeInformation
+ [Statement("fnc", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
+ public void FindFunction(string args)
{
- [Statement("fnc", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
- public void FindFunction(string args)
+ if (RuntimeInfo.InternalIsInFunction)
{
- if (RuntimeInfo.InternalIsInFunction)
- {
- RuntimeInfo.Exit("Nested functions are not allowed", true);
- return;
- }
-
- string key = args.Trim();
- if (RuntimeInfo.Functions.ContainsKey(key))
- {
- RuntimeInfo.Functions[key] = RuntimeInfo.LineNumber;
- }
- else
- {
- RuntimeInfo.Functions.Add(key, RuntimeInfo.LineNumber);
- }
-
- if (!string.IsNullOrWhiteSpace(RuntimeInfo.SearchFunction) && RuntimeInfo.SearchFunction == key)
- {
- RuntimeInfo.SearchFunction = string.Empty;
- }
-
- RuntimeInfo.IsInFunction = true;
+ RuntimeInfo.Exit("Nested functions are not allowed", true);
+ return;
}
- [Statement("in", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
- public void AddInParameter(string args)
+ string key = args.Trim();
+ if (RuntimeInfo.Functions.ContainsKey(key))
{
- RuntimeInfo.InParametersStack.Push(args);
+ RuntimeInfo.Functions[key] = RuntimeInfo.LineNumber;
+ }
+ else
+ {
+ RuntimeInfo.Functions.Add(key, RuntimeInfo.LineNumber);
}
- [Statement("out", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
- public void GetOutParameter(string args)
+ if (!string.IsNullOrWhiteSpace(RuntimeInfo.SearchFunction) && RuntimeInfo.SearchFunction == key)
{
- if (RuntimeInfo.OutParametersStack.Count == 0)
- {
- RuntimeInfo.Exit("No out argument in stack", true);
- return;
- }
-
- if (RuntimeInfo.Variables.ContainsKey(args))
- {
- RuntimeInfo.Variables[args] = RuntimeInfo.OutParametersStack.Pop();
- }
- else
- {
- RuntimeInfo.Variables.Add(args, RuntimeInfo.OutParametersStack.Pop());
- }
+ RuntimeInfo.SearchFunction = string.Empty;
}
- [Statement("%iso", SearchMode.Contains, SpaceAround.None, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
- public void CheckIfOutParameterAvalible(string args)
- {
- args += " ";
- args = args.Replace("%iso", (RuntimeInfo.OutParametersStack.Count > 0).ToString());
+ RuntimeInfo.IsInFunction = true;
+ }
- RuntimeInfo.CurrentLine = args.TrimEnd();
+ [Statement("in", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
+ public void AddInParameter(string args)
+ {
+ RuntimeInfo.InParametersStack.Push(args);
+ }
+
+ [Statement("out", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
+ public void GetOutParameter(string args)
+ {
+ if (RuntimeInfo.OutParametersStack.Count == 0)
+ {
+ RuntimeInfo.Exit("No out argument in stack", true);
+ return;
}
- [Statement("cal", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, Priority = Priority.Low, Seperator = "|")]
- public void Call(string args)
+ if (RuntimeInfo.Variables.ContainsKey(args))
{
- string[] parts = args.Split('|');
- if (parts.Length != 2)
- {
- RuntimeInfo.Exit("Invalid syntax", true);
- return;
- }
-
- string key = parts[0].Trim();
- string[] functionArgumets = parts[1].Split(',');
-
- foreach (string argumanet in functionArgumets)
- {
- RuntimeInfo.InParametersStack.Push(argumanet.Trim());
- }
-
- RuntimeInfo.FunctionCallStack.Push(new FunctionScope(RuntimeInfo.LineNumber, new Stack(RuntimeInfo.InParametersStack)));
- RuntimeInfo.InParametersStack.Clear();
- RuntimeInfo.CurrentLine = string.Empty;
-
- if (RuntimeInfo.Functions.ContainsKey(key))
- {
- RuntimeInfo.LineNumber = RuntimeInfo.Functions[key];
- }
- else
- {
- RuntimeInfo.SearchFunction = key;
- }
+ RuntimeInfo.Variables[args] = RuntimeInfo.OutParametersStack.Pop();
}
-
- [Statement("get", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
- public void GetInParameter(string args)
+ else
{
- if (!RuntimeInfo.IsInFunction)
- {
- RuntimeInfo.Exit("Statement not allowed outside of function", true);
- return;
- }
-
- if (RuntimeInfo.FunctionCallStack.Peek().Arguemtns.Count == 0)
- {
- RuntimeInfo.Exit("No in argument in stack", true);
- return;
- }
-
- if (RuntimeInfo.Variables.ContainsKey(args))
- {
- RuntimeInfo.Variables[args] = RuntimeInfo.FunctionCallStack.Peek().Arguemtns.Pop();
- }
- else
- {
- RuntimeInfo.Variables.Add(args, RuntimeInfo.FunctionCallStack.Peek().Arguemtns.Pop());
- }
- }
-
- [Statement("%isi", SearchMode.Contains, SpaceAround.End, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
- public void CheckIfInParameterAvalible(string args)
- {
- if (!RuntimeInfo.IsInFunction)
- {
- RuntimeInfo.Exit("Statement not allowed outside of function", true);
- return;
- }
-
- args += " ";
- args = args.Replace("%isi", (RuntimeInfo.FunctionCallStack.Peek().Arguemtns.Count > 0).ToString());
-
- RuntimeInfo.CurrentLine = args.TrimEnd();
- }
-
- [Statement("put", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
- public void AddOutParameter(string args)
- {
- if (!RuntimeInfo.IsInFunction)
- {
- RuntimeInfo.Exit("Statement not allowed outside of function", true);
- return;
- }
-
- RuntimeInfo.FunctionCallStack.Peek().Results.Push(args);
- }
-
- [Statement("ret", SearchMode.Exact, SpaceAround.None, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
- public void Return(string _)
- {
- if (!RuntimeInfo.IsInFunction)
- {
- RuntimeInfo.Exit("Statement not allowed outside of function", true);
- return;
- }
-
- if (RuntimeInfo.IsSearching)
- {
- RuntimeInfo.IsInFunction = false;
-
- if (RuntimeInfo.IsLocalSearch)
- {
- RuntimeInfo.Exit($"Label \"{RuntimeInfo.SearchLabel}\" not found", true);
- }
- return;
- }
- else
- {
- RuntimeInfo.IsInFunction = false;
- }
-
- if (RuntimeInfo.FunctionCallStack.Count > 0)
- {
- FunctionScope functionScope = RuntimeInfo.FunctionCallStack.Pop();
-
- RuntimeInfo.OutParametersStack = new Stack(functionScope.Results);
- RuntimeInfo.LineNumber = functionScope.CallerLine;
- }
- else
- {
- RuntimeInfo.Exit("No function in stack", true);
- }
- }
-
- [Statement("ccs", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red)]
- public void ClearCallStack(string _)
- {
- RuntimeInfo.FunctionCallStack.Clear();
+ RuntimeInfo.Variables.Add(args, RuntimeInfo.OutParametersStack.Pop());
}
}
+
+ [Statement("%iso", SearchMode.Contains, SpaceAround.None, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ public void CheckIfOutParameterAvailable(string args)
+ {
+ args += " ";
+ args = args.Replace("%iso", (RuntimeInfo.OutParametersStack.Count > 0).ToString());
+
+ RuntimeInfo.CurrentLine = args.TrimEnd();
+ }
+
+ [Statement("cal", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, Priority = Priority.Low, Separator = "|")]
+ public void Call(string args)
+ {
+ string[] parts = args.Split('|');
+ if (parts.Length != 2)
+ {
+ RuntimeInfo.Exit("Invalid syntax", true);
+ return;
+ }
+
+ string key = parts[0].Trim();
+ string[] functionArguments = parts[1].Split(',');
+
+ foreach (string argument in functionArguments)
+ {
+ RuntimeInfo.InParametersStack.Push(argument.Trim());
+ }
+
+ RuntimeInfo.FunctionCallStack.Push(new FunctionScope(RuntimeInfo.LineNumber, new Stack(RuntimeInfo.InParametersStack)));
+ RuntimeInfo.InParametersStack.Clear();
+ RuntimeInfo.CurrentLine = string.Empty;
+
+ if (RuntimeInfo.Functions.TryGetValue(key, out int value))
+ {
+ RuntimeInfo.LineNumber = value;
+ }
+ else
+ {
+ RuntimeInfo.SearchFunction = key;
+ }
+ }
+
+ [Statement("get", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
+ public void GetInParameter(string args)
+ {
+ if (!RuntimeInfo.IsInFunction)
+ {
+ RuntimeInfo.Exit("Statement not allowed outside of function", true);
+ return;
+ }
+
+ if (RuntimeInfo.FunctionCallStack.Peek().Arguments.Count == 0)
+ {
+ RuntimeInfo.Exit("No in argument in stack", true);
+ return;
+ }
+
+ if (RuntimeInfo.Variables.ContainsKey(args))
+ {
+ RuntimeInfo.Variables[args] = RuntimeInfo.FunctionCallStack.Peek().Arguments.Pop();
+ }
+ else
+ {
+ RuntimeInfo.Variables.Add(args, RuntimeInfo.FunctionCallStack.Peek().Arguments.Pop());
+ }
+ }
+
+ [Statement("%isi", SearchMode.Contains, SpaceAround.End, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ public void CheckIfInParameterAvailable(string args)
+ {
+ if (!RuntimeInfo.IsInFunction)
+ {
+ RuntimeInfo.Exit("Statement not allowed outside of function", true);
+ return;
+ }
+
+ args += " ";
+ args = args.Replace("%isi", (RuntimeInfo.FunctionCallStack.Peek().Arguments.Count > 0).ToString());
+
+ RuntimeInfo.CurrentLine = args.TrimEnd();
+ }
+
+ [Statement("put", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
+ public void AddOutParameter(string args)
+ {
+ if (!RuntimeInfo.IsInFunction)
+ {
+ RuntimeInfo.Exit("Statement not allowed outside of function", true);
+ return;
+ }
+
+ RuntimeInfo.FunctionCallStack.Peek().Results.Push(args);
+ }
+
+ [Statement("ret", SearchMode.Exact, SpaceAround.None, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
+ public void Return(string _)
+ {
+ if (!RuntimeInfo.IsInFunction)
+ {
+ RuntimeInfo.Exit("Statement not allowed outside of function", true);
+ return;
+ }
+
+ if (RuntimeInfo.IsSearching)
+ {
+ RuntimeInfo.IsInFunction = false;
+
+ if (RuntimeInfo.IsLocalSearch)
+ {
+ RuntimeInfo.Exit($"Label \"{RuntimeInfo.SearchLabel}\" not found", true);
+ }
+ return;
+ }
+ else
+ {
+ RuntimeInfo.IsInFunction = false;
+ }
+
+ if (RuntimeInfo.FunctionCallStack.Count > 0)
+ {
+ FunctionScope functionScope = RuntimeInfo.FunctionCallStack.Pop();
+
+ RuntimeInfo.OutParametersStack = new Stack(functionScope.Results);
+ RuntimeInfo.LineNumber = functionScope.CallerLine;
+ }
+ else
+ {
+ RuntimeInfo.Exit("No function in stack", true);
+ }
+ }
+
+ [Statement("ccs", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red)]
+ public void ClearCallStack(string _)
+ {
+ RuntimeInfo.FunctionCallStack.Clear();
+ }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Statements/PredifinedVariableStatements.cs b/YesNt.Interpreter/Statements/PredifinedVariableStatements.cs
index 6740f44..e79276f 100644
--- a/YesNt.Interpreter/Statements/PredifinedVariableStatements.cs
+++ b/YesNt.Interpreter/Statements/PredifinedVariableStatements.cs
@@ -5,61 +5,60 @@ using YesNt.Interpreter.Enums;
using YesNt.Interpreter.Runtime;
using YesNt.Interpreter.Utilities;
-namespace YesNt.Interpreter.Statements
+namespace YesNt.Interpreter.Statements;
+
+internal class PredefinedVariableStatements : StatementRuntimeInformation
{
- internal class PredifinedVariableStatements : StatementRuntimeInformation
+ private readonly Random random = new Random();
+
+ [Statement("%time", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ public void GetUnixTimestamp(string args)
{
- private readonly Random random = new Random();
+ args = args.Replace("%time", DateTimeOffset.Now.ToUnixTimeSeconds().ToString());
- [Statement("%time", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
- public void GetUnixTimestamp(string args)
+ RuntimeInfo.CurrentLine = args.TrimEnd();
+ }
+
+ [Statement("%os", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ public void GetOperatingSystem(string args)
+ {
+ args = args.Replace("%os", Environment.OSVersion.Platform.ToString());
+
+ RuntimeInfo.CurrentLine = args.TrimEnd();
+ }
+
+ [Statement("%cpu", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ public void GetProcessorArchitecture(string args)
+ {
+ args = args.Replace("%cpu", System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture.ToString());
+
+ RuntimeInfo.CurrentLine = args.TrimEnd();
+ }
+
+ [Statement("%is64", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ public void GetIsOperatingSystem64Bit(string args)
+ {
+ args = args.Replace("%is64", $"{Environment.Is64BitOperatingSystem}");
+
+ RuntimeInfo.CurrentLine = args.TrimEnd();
+ }
+
+ [Statement("%pi", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ public void GetPi(string args)
+ {
+ args = args.Replace("%pi", Math.PI.ToString());
+
+ RuntimeInfo.CurrentLine = args.TrimEnd();
+ }
+
+ [Statement("%rnd", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ public void GetRandom(string args)
+ {
+ while (args.Contains("%rnd"))
{
- args = args.Replace("%time", DateTimeOffset.Now.ToUnixTimeSeconds().ToString());
-
- RuntimeInfo.CurrentLine = args.TrimEnd();
+ args = args.ReplaceFirstOccurrence("%rnd", random.Next(32767, int.MaxValue).ToString());
}
- [Statement("%os", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
- public void GetOperatingSystem(string args)
- {
- args = args.Replace("%os", Environment.OSVersion.Platform.ToString());
-
- RuntimeInfo.CurrentLine = args.TrimEnd();
- }
-
- [Statement("%cpu", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
- public void GetProcessorArchitecture(string args)
- {
- args = args.Replace("%cpu", System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture.ToString());
-
- RuntimeInfo.CurrentLine = args.TrimEnd();
- }
-
- [Statement("%is64", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
- public void GetIsOperatingSystem64Bit(string args)
- {
- args = args.Replace("%is64", $"{Environment.Is64BitOperatingSystem}");
-
- RuntimeInfo.CurrentLine = args.TrimEnd();
- }
-
- [Statement("%pi", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
- public void GetPi(string args)
- {
- args = args.Replace("%pi", Math.PI.ToString());
-
- RuntimeInfo.CurrentLine = args.TrimEnd();
- }
-
- [Statement("%rnd", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
- public void GetRandom(string args)
- {
- while (args.Contains("%rnd"))
- {
- args = args.ReplaceFirstOccurrence("%rnd", random.Next(32767, int.MaxValue).ToString());
- }
-
- RuntimeInfo.CurrentLine = args.TrimEnd();
- }
+ RuntimeInfo.CurrentLine = args.TrimEnd();
}
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Statements/ProcessingStatements.cs b/YesNt.Interpreter/Statements/ProcessingStatements.cs
index 54cebf4..e606aea 100644
--- a/YesNt.Interpreter/Statements/ProcessingStatements.cs
+++ b/YesNt.Interpreter/Statements/ProcessingStatements.cs
@@ -41,17 +41,17 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
[Statement("!task", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.VeryHigh)]
public void RunTask(string line)
{
- int lineNumer = RuntimeInfo.LineNumber;
+ int lineNumber = RuntimeInfo.LineNumber;
List lines = RuntimeInfo.Lines.GetRange(0, RuntimeInfo.Lines.Count);
- Line oldLine = lines[lineNumer];
+ Line oldLine = lines[lineNumber];
- lines[lineNumer] = new Line(line, oldLine.FileName, oldLine.LineNumber);
+ lines[lineNumber] = new Line(line, oldLine.FileName, oldLine.LineNumber);
_ = Task.Run(() =>
{
YesNtInterpreter interpreter = new YesNtInterpreter();
interpreter.Initialize();
- interpreter.Execute(lines, RuntimeInfo.GloablVariables, lineNumer, RuntimeInfo);
+ interpreter.Execute(lines, RuntimeInfo.GlobalVariables, lineNumber, RuntimeInfo);
});
RuntimeInfo.CurrentLine = string.Empty;
diff --git a/YesNt.Interpreter/Statements/SystemStatements.cs b/YesNt.Interpreter/Statements/SystemStatements.cs
index cdf66ec..c8d1e32 100644
--- a/YesNt.Interpreter/Statements/SystemStatements.cs
+++ b/YesNt.Interpreter/Statements/SystemStatements.cs
@@ -9,105 +9,104 @@ using YesNt.Interpreter.Enums;
using YesNt.Interpreter.Runtime;
using YesNt.Interpreter.Utilities;
-namespace YesNt.Interpreter.Statements
+namespace YesNt.Interpreter.Statements;
+
+internal class SystemStatements : StatementRuntimeInformation
{
- internal class SystemStatements : StatementRuntimeInformation
+ [Statement("exc", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta, Priority = Priority.Low, Separator = "|")]
+ public void ExecuteProgramWithArgs(string input)
{
- [Statement("exc", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta, Priority = Priority.Low, Seperator = "|")]
- public void ExecuteProgramWithArgs(string input)
+ string[] parts = input.FromSafeString().Split('|');
+ parts[0] = parts[0].Trim();
+
+ string[] functionArguments = parts[1].Split(',');
+
+ foreach (string argument in functionArguments)
{
- string[] parts = input.FromSafeString().Split('|');
- parts[0] = parts[0].Trim();
-
- string[] functionArgumets = parts[1].Split(',');
-
- foreach (string argumanet in functionArgumets)
- {
- RuntimeInfo.InParametersStack.Push(argumanet.Trim());
- }
-
- try
- {
- StartProcess(parts[0], string.Join(string.Empty, RuntimeInfo.InParametersStack.Reverse()));
- }
- catch (FileNotFoundException)
- {
- RuntimeInfo.Exit($"Cannot find file \"{parts[0]}\".", false);
- }
- catch (Win32Exception ex)
- {
- RuntimeInfo.Exit($"Failed to start \"{parts[0]}\". {ex.Message}", false);
- }
-
- //HACK: Clear line to avoid execution from other "exc" statement
- RuntimeInfo.CurrentLine = string.Empty;
+ RuntimeInfo.InParametersStack.Push(argument.Trim());
}
- [Statement("exc", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta, Priority = Priority.VeryLow)]
- public void ExecuteProgram(string input)
+ try
{
- try
- {
- StartProcess(input, string.Join(string.Empty, RuntimeInfo.InParametersStack.Reverse()));
- }
- catch (FileNotFoundException)
- {
- RuntimeInfo.Exit($"Cannot find file \"{input}\".", false);
- }
- catch (Win32Exception ex)
- {
- RuntimeInfo.Exit($"Failed to start \"{input}\". {ex.Message}", false);
- }
+ StartProcess(parts[0], string.Join(string.Empty, RuntimeInfo.InParametersStack.Reverse()));
+ }
+ catch (FileNotFoundException)
+ {
+ RuntimeInfo.Exit($"Cannot find file \"{parts[0]}\".", false);
+ }
+ catch (Win32Exception ex)
+ {
+ RuntimeInfo.Exit($"Failed to start \"{parts[0]}\". {ex.Message}", false);
}
- private void StartProcess(string name, string args)
+ //HACK: Clear line to avoid execution from other "exc" statement
+ RuntimeInfo.CurrentLine = string.Empty;
+ }
+
+ [Statement("exc", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta, Priority = Priority.VeryLow)]
+ public void ExecuteProgram(string input)
+ {
+ try
{
- RuntimeInfo.OutParametersStack.Clear();
-
- FixedProcess process = new FixedProcess
- {
- StartInfo = new ProcessStartInfo()
- {
- FileName = name,
- Arguments = args,
- RedirectStandardOutput = true,
- RedirectStandardError = true
- }
- };
-
- process.OutputDataReceived += Process_OutputDataReceived;
- process.ErrorDataReceived += Process_ErrorDataReceived;
-
- _ = process.Start();
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
- process.WaitForExit();
-
- RuntimeInfo.InParametersStack.Clear();
-
- RuntimeInfo.OutParametersStack.Push(process.ExitCode.ToString());
+ StartProcess(input, string.Join(string.Empty, RuntimeInfo.InParametersStack.Reverse()));
}
-
- private void Process_ErrorDataReceived(object sender, Utilities.DataReceivedEventArgs e)
+ catch (FileNotFoundException)
{
- if (string.IsNullOrWhiteSpace(e.Data))
- {
- return;
- }
-
- RuntimeInfo.OutParametersStack.Push(e.Data);
- Console.Write("Error: " + e.Data);
+ RuntimeInfo.Exit($"Cannot find file \"{input}\".", false);
}
-
- private void Process_OutputDataReceived(object sender, Utilities.DataReceivedEventArgs e)
+ catch (Win32Exception ex)
{
- if (string.IsNullOrWhiteSpace(e.Data))
- {
- return;
- }
-
- RuntimeInfo.OutParametersStack.Push(e.Data);
- Console.Write(e.Data);
+ RuntimeInfo.Exit($"Failed to start \"{input}\". {ex.Message}", false);
}
}
+
+ private void StartProcess(string name, string args)
+ {
+ RuntimeInfo.OutParametersStack.Clear();
+
+ FixedProcess process = new FixedProcess
+ {
+ StartInfo = new ProcessStartInfo()
+ {
+ FileName = name,
+ Arguments = args,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true
+ }
+ };
+
+ process.OutputDataReceived += Process_OutputDataReceived;
+ process.ErrorDataReceived += Process_ErrorDataReceived;
+
+ _ = process.Start();
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+ process.WaitForExit();
+
+ RuntimeInfo.InParametersStack.Clear();
+
+ RuntimeInfo.OutParametersStack.Push(process.ExitCode.ToString());
+ }
+
+ private void Process_ErrorDataReceived(object sender, Utilities.DataReceivedEventArgs e)
+ {
+ if (string.IsNullOrWhiteSpace(e.Data))
+ {
+ return;
+ }
+
+ RuntimeInfo.OutParametersStack.Push(e.Data);
+ Console.Write("Error: " + e.Data);
+ }
+
+ private void Process_OutputDataReceived(object sender, Utilities.DataReceivedEventArgs e)
+ {
+ if (string.IsNullOrWhiteSpace(e.Data))
+ {
+ return;
+ }
+
+ RuntimeInfo.OutParametersStack.Push(e.Data);
+ Console.Write(e.Data);
+ }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Statements/VariableStatements.cs b/YesNt.Interpreter/Statements/VariableStatements.cs
index 5fd4c5d..dba0c93 100644
--- a/YesNt.Interpreter/Statements/VariableStatements.cs
+++ b/YesNt.Interpreter/Statements/VariableStatements.cs
@@ -47,13 +47,13 @@ internal partial class VariableStatements : StatementRuntimeInformation
RuntimeInfo.Exit("Invalid Syntax", true);
}
- if (RuntimeInfo.GloablVariables.ContainsKey(key))
+ if (RuntimeInfo.GlobalVariables.ContainsKey(key))
{
- RuntimeInfo.GloablVariables[key] = parts[1].Trim();
+ RuntimeInfo.GlobalVariables[key] = parts[1].Trim();
}
else
{
- RuntimeInfo.GloablVariables.Add(key, parts[1].Trim());
+ RuntimeInfo.GlobalVariables.Add(key, parts[1].Trim());
}
}
else
@@ -71,9 +71,9 @@ internal partial class VariableStatements : StatementRuntimeInformation
{
_ = RuntimeInfo.Variables.Remove(key);
}
- else if (RuntimeInfo.GloablVariables.ContainsKey(key))
+ else if (RuntimeInfo.GlobalVariables.ContainsKey(key))
{
- _ = RuntimeInfo.GloablVariables.Remove(key);
+ _ = RuntimeInfo.GlobalVariables.Remove(key);
}
else
{
@@ -103,7 +103,7 @@ internal partial class VariableStatements : StatementRuntimeInformation
{
RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{varName}", value);
}
- else if (RuntimeInfo.GloablVariables.TryGetValue(varName, out value))
+ else if (RuntimeInfo.GlobalVariables.TryGetValue(varName, out value))
{
RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{varName}", value);
}
diff --git a/YesNt.Interpreter/Utilities/FixedProcess.cs b/YesNt.Interpreter/Utilities/FixedProcess.cs
index 46ee530..1117d27 100644
--- a/YesNt.Interpreter/Utilities/FixedProcess.cs
+++ b/YesNt.Interpreter/Utilities/FixedProcess.cs
@@ -5,312 +5,311 @@ using System.IO;
using System.Text;
using System.Threading;
-namespace YesNt.Interpreter.Utilities
+namespace YesNt.Interpreter.Utilities;
+
+public delegate void DataReceivedEventHandler(object sender, DataReceivedEventArgs e);
+
+internal delegate void UserCallBack(string data);
+
+public class FixedProcess : Process
{
- internal delegate void UserCallBack(string data);
+ public new event DataReceivedEventHandler OutputDataReceived;
- public delegate void DataReceivedEventHandler(object sender, DataReceivedEventArgs e);
+ public new event DataReceivedEventHandler ErrorDataReceived;
- public class FixedProcess : Process
+ internal AsyncStreamReader output;
+ internal AsyncStreamReader error;
+
+ public new void BeginOutputReadLine()
{
- internal AsyncStreamReader output;
- internal AsyncStreamReader error;
-
- public new event DataReceivedEventHandler OutputDataReceived;
-
- public new event DataReceivedEventHandler ErrorDataReceived;
-
- public new void BeginOutputReadLine()
- {
- Stream baseStream = StandardOutput.BaseStream;
- output = new AsyncStreamReader(baseStream, new UserCallBack(FixedOutputReadNotifyUser), StandardOutput.CurrentEncoding);
- output.BeginReadLine();
- }
-
- public new void BeginErrorReadLine()
- {
- Stream baseStream = StandardError.BaseStream;
- error = new AsyncStreamReader(baseStream, new UserCallBack(FixedErrorReadNotifyUser), StandardError.CurrentEncoding);
- error.BeginReadLine();
- }
-
- internal void FixedOutputReadNotifyUser(string data)
- {
- DataReceivedEventHandler outputDataReceived = OutputDataReceived;
- if (outputDataReceived != null)
- {
- DataReceivedEventArgs dataReceivedEventArgs = new DataReceivedEventArgs(data);
- if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
- {
- _ = SynchronizingObject.Invoke(outputDataReceived, new object[]
- {
- this,
- dataReceivedEventArgs
- });
- return;
- }
- outputDataReceived(this, dataReceivedEventArgs);
- }
- }
-
- internal void FixedErrorReadNotifyUser(string data)
- {
- DataReceivedEventHandler errorDataReceived = ErrorDataReceived;
- if (errorDataReceived != null)
- {
- DataReceivedEventArgs dataReceivedEventArgs = new DataReceivedEventArgs(data);
- if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
- {
- _ = SynchronizingObject.Invoke(errorDataReceived, new object[]
- {
- this,
- dataReceivedEventArgs
- });
- return;
- }
- errorDataReceived(this, dataReceivedEventArgs);
- }
- }
+ Stream baseStream = StandardOutput.BaseStream;
+ output = new AsyncStreamReader(baseStream, new UserCallBack(FixedOutputReadNotifyUser), StandardOutput.CurrentEncoding);
+ output.BeginReadLine();
}
- internal class AsyncStreamReader : IDisposable
+ public new void BeginErrorReadLine()
{
- internal const int DefaultBufferSize = 1024;
- private Stream stream;
- private Encoding encoding;
- private Decoder decoder;
- private byte[] byteBuffer;
- private char[] charBuffer;
- private UserCallBack userCallBack;
- private bool cancelOperation;
- private ManualResetEvent eofEvent;
- private readonly Queue messageQueue;
- private StringBuilder sb;
- private bool bLastCarriageReturn;
- public virtual Encoding CurrentEncoding => encoding;
- public virtual Stream BaseStream => stream;
+ Stream baseStream = StandardError.BaseStream;
+ error = new AsyncStreamReader(baseStream, new UserCallBack(FixedErrorReadNotifyUser), StandardError.CurrentEncoding);
+ error.BeginReadLine();
+ }
- internal AsyncStreamReader(Stream stream, UserCallBack callback, Encoding encoding) : this(stream, callback, encoding, 1024)
+ internal void FixedOutputReadNotifyUser(string data)
+ {
+ DataReceivedEventHandler outputDataReceived = OutputDataReceived;
+ if (outputDataReceived != null)
{
- }
-
- internal AsyncStreamReader(Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
- {
- Init(stream, callback, encoding, bufferSize);
- messageQueue = new Queue();
- }
-
- private void Init(Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
- {
- this.stream = stream;
- this.encoding = encoding;
- userCallBack = callback;
- decoder = encoding.GetDecoder();
- if (bufferSize < 128)
+ DataReceivedEventArgs dataReceivedEventArgs = new DataReceivedEventArgs(data);
+ if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
{
- bufferSize = 128;
- }
- byteBuffer = new byte[bufferSize];
- int _maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize);
- charBuffer = new char[_maxCharsPerBuffer];
- cancelOperation = false;
- eofEvent = new ManualResetEvent(false);
- sb = null;
- bLastCarriageReturn = false;
- }
-
- public virtual void Close()
- {
- Dispose(true);
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (disposing && stream != null)
- {
- stream.Close();
- }
- if (stream != null)
- {
- stream = null;
- encoding = null;
- decoder = null;
- byteBuffer = null;
- charBuffer = null;
- }
- if (eofEvent != null)
- {
- eofEvent.Close();
- eofEvent = null;
- }
- }
-
- internal void BeginReadLine()
- {
- if (cancelOperation)
- {
- cancelOperation = false;
- }
- if (sb == null)
- {
- sb = new StringBuilder(1024);
- _ = stream.BeginRead(byteBuffer, 0, byteBuffer.Length, new AsyncCallback(ReadBuffer), null);
+ _ = SynchronizingObject.Invoke(outputDataReceived,
+ [
+ this,
+ dataReceivedEventArgs
+ ]);
return;
}
- FlushMessageQueue();
- }
-
- internal void CancelOperation()
- {
- cancelOperation = true;
- }
-
- private void ReadBuffer(IAsyncResult ar)
- {
- int num;
- try
- {
- num = stream.EndRead(ar);
- }
- catch (IOException)
- {
- num = 0;
- }
- catch (OperationCanceledException)
- {
- num = 0;
- }
- if (num == 0)
- {
- lock (messageQueue)
- {
- if (sb.Length != 0)
- {
- messageQueue.Enqueue(sb.ToString());
- sb.Length = 0;
- }
- messageQueue.Enqueue(null);
- }
- try
- {
- FlushMessageQueue();
- return;
- }
- finally
- {
- _ = eofEvent.Set();
- }
- }
- int chars = decoder.GetChars(byteBuffer, 0, num, charBuffer, 0);
- _ = sb.Append(charBuffer, 0, chars);
- GetLinesFromStringBuilder();
- _ = stream.BeginRead(byteBuffer, 0, byteBuffer.Length, new AsyncCallback(ReadBuffer), null);
- }
-
- private void GetLinesFromStringBuilder()
- {
- int i = 0;
- int num = 0;
- int length = sb.Length;
- if (bLastCarriageReturn && length > 0 && sb[0] == '\n')
- {
- i = 1;
- num = 1;
- bLastCarriageReturn = false;
- }
- while (i < length)
- {
- char c = sb[i];
- if (c is '\r' or '\n')
- {
- if (c == '\r' && i + 1 < length && sb[i + 1] == '\n')
- {
- i++;
- }
-
- string obj = sb.ToString(num, i + 1 - num);
-
- num = i + 1;
-
- lock (messageQueue)
- {
- messageQueue.Enqueue(obj);
- }
- }
- i++;
- }
-
- // Flush Fix: Send Whatever is left in the buffer
- string endOfBuffer = sb.ToString(num, length - num);
- lock (messageQueue)
- {
- messageQueue.Enqueue(endOfBuffer);
- num = length;
- }
- // End Flush Fix
-
- if (sb[length - 1] == '\r')
- {
- bLastCarriageReturn = true;
- }
- if (num < length)
- {
- _ = sb.Remove(0, num);
- }
- else
- {
- sb.Length = 0;
- }
- FlushMessageQueue();
- }
-
- private void FlushMessageQueue()
- {
- while (messageQueue.Count > 0)
- {
- lock (messageQueue)
- {
- if (messageQueue.Count > 0)
- {
- string data = (string)messageQueue.Dequeue();
- if (!cancelOperation)
- {
- userCallBack(data);
- }
- }
- }
- }
- }
-
- internal void WaitUtilEOF()
- {
- if (eofEvent != null)
- {
- _ = eofEvent.WaitOne();
- eofEvent.Close();
- eofEvent = null;
- }
+ outputDataReceived(this, dataReceivedEventArgs);
}
}
- public class DataReceivedEventArgs : EventArgs
+ internal void FixedErrorReadNotifyUser(string data)
{
- internal string _data;
-
- /// Gets the line of characters that was written to a redirected output stream.
- /// The line that was written by an associated to its redirected or stream.
- /// 2
- public string Data => _data;
-
- internal DataReceivedEventArgs(string data)
+ DataReceivedEventHandler errorDataReceived = ErrorDataReceived;
+ if (errorDataReceived != null)
{
- _data = data;
+ DataReceivedEventArgs dataReceivedEventArgs = new DataReceivedEventArgs(data);
+ if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
+ {
+ _ = SynchronizingObject.Invoke(errorDataReceived,
+ [
+ this,
+ dataReceivedEventArgs
+ ]);
+ return;
+ }
+ errorDataReceived(this, dataReceivedEventArgs);
+ }
+ }
+}
+
+public class DataReceivedEventArgs : EventArgs
+{
+ internal string _data;
+
+ /// Gets the line of characters that was written to a redirected output stream.
+ /// The line that was written by an associated to its redirected or stream.
+ /// 2
+ public string Data => _data;
+
+ internal DataReceivedEventArgs(string data)
+ {
+ _data = data;
+ }
+}
+
+internal class AsyncStreamReader : IDisposable
+{
+ internal const int DefaultBufferSize = 1024;
+ private readonly Queue messageQueue;
+ private Stream stream;
+ private Encoding encoding;
+ private Decoder decoder;
+ private byte[] byteBuffer;
+ private char[] charBuffer;
+ private UserCallBack userCallBack;
+ private bool cancelOperation;
+ private ManualResetEvent eofEvent;
+ private StringBuilder sb;
+ private bool bLastCarriageReturn;
+ public virtual Encoding CurrentEncoding => encoding;
+ public virtual Stream BaseStream => stream;
+
+ internal AsyncStreamReader(Stream stream, UserCallBack callback, Encoding encoding) : this(stream, callback, encoding, 1024)
+ {
+ }
+
+ internal AsyncStreamReader(Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
+ {
+ Init(stream, callback, encoding, bufferSize);
+ messageQueue = new Queue();
+ }
+
+ public virtual void Close()
+ {
+ Dispose(true);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ internal void BeginReadLine()
+ {
+ if (cancelOperation)
+ {
+ cancelOperation = false;
+ }
+ if (sb == null)
+ {
+ sb = new StringBuilder(1024);
+ _ = stream.BeginRead(byteBuffer, 0, byteBuffer.Length, new AsyncCallback(ReadBuffer), null);
+ return;
+ }
+ FlushMessageQueue();
+ }
+
+ internal void CancelOperation()
+ {
+ cancelOperation = true;
+ }
+
+ internal void WaitUtilEOF()
+ {
+ if (eofEvent != null)
+ {
+ _ = eofEvent.WaitOne();
+ eofEvent.Close();
+ eofEvent = null;
+ }
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing && stream != null)
+ {
+ stream.Close();
+ }
+ if (stream != null)
+ {
+ stream = null;
+ encoding = null;
+ decoder = null;
+ byteBuffer = null;
+ charBuffer = null;
+ }
+ if (eofEvent != null)
+ {
+ eofEvent.Close();
+ eofEvent = null;
+ }
+ }
+
+ private void Init(Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
+ {
+ this.stream = stream;
+ this.encoding = encoding;
+ userCallBack = callback;
+ decoder = encoding.GetDecoder();
+ if (bufferSize < 128)
+ {
+ bufferSize = 128;
+ }
+ byteBuffer = new byte[bufferSize];
+ int _maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize);
+ charBuffer = new char[_maxCharsPerBuffer];
+ cancelOperation = false;
+ eofEvent = new ManualResetEvent(false);
+ sb = null;
+ bLastCarriageReturn = false;
+ }
+
+ private void ReadBuffer(IAsyncResult ar)
+ {
+ int num;
+ try
+ {
+ num = stream.EndRead(ar);
+ }
+ catch (IOException)
+ {
+ num = 0;
+ }
+ catch (OperationCanceledException)
+ {
+ num = 0;
+ }
+ if (num == 0)
+ {
+ lock (messageQueue)
+ {
+ if (sb.Length != 0)
+ {
+ messageQueue.Enqueue(sb.ToString());
+ sb.Length = 0;
+ }
+ messageQueue.Enqueue(null);
+ }
+ try
+ {
+ FlushMessageQueue();
+ return;
+ }
+ finally
+ {
+ _ = eofEvent.Set();
+ }
+ }
+ int chars = decoder.GetChars(byteBuffer, 0, num, charBuffer, 0);
+ _ = sb.Append(charBuffer, 0, chars);
+ GetLinesFromStringBuilder();
+ _ = stream.BeginRead(byteBuffer, 0, byteBuffer.Length, new AsyncCallback(ReadBuffer), null);
+ }
+
+ private void GetLinesFromStringBuilder()
+ {
+ int i = 0;
+ int num = 0;
+ int length = sb.Length;
+ if (bLastCarriageReturn && length > 0 && sb[0] == '\n')
+ {
+ i = 1;
+ num = 1;
+ bLastCarriageReturn = false;
+ }
+ while (i < length)
+ {
+ char c = sb[i];
+ if (c is '\r' or '\n')
+ {
+ if (c == '\r' && i + 1 < length && sb[i + 1] == '\n')
+ {
+ i++;
+ }
+
+ string obj = sb.ToString(num, i + 1 - num);
+
+ num = i + 1;
+
+ lock (messageQueue)
+ {
+ messageQueue.Enqueue(obj);
+ }
+ }
+ i++;
+ }
+
+ // Flush Fix: Send Whatever is left in the buffer
+ string endOfBuffer = sb.ToString(num, length - num);
+ lock (messageQueue)
+ {
+ messageQueue.Enqueue(endOfBuffer);
+ num = length;
+ }
+ // End Flush Fix
+
+ if (sb[length - 1] == '\r')
+ {
+ bLastCarriageReturn = true;
+ }
+ if (num < length)
+ {
+ _ = sb.Remove(0, num);
+ }
+ else
+ {
+ sb.Length = 0;
+ }
+ FlushMessageQueue();
+ }
+
+ private void FlushMessageQueue()
+ {
+ while (messageQueue.Count > 0)
+ {
+ lock (messageQueue)
+ {
+ if (messageQueue.Count > 0)
+ {
+ string data = (string)messageQueue.Dequeue();
+ if (!cancelOperation)
+ {
+ userCallBack(data);
+ }
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Utilities/StringExtentions.cs b/YesNt.Interpreter/Utilities/StringExtentions.cs
index ca042b8..0feb116 100644
--- a/YesNt.Interpreter/Utilities/StringExtentions.cs
+++ b/YesNt.Interpreter/Utilities/StringExtentions.cs
@@ -7,7 +7,7 @@ using System.Text;
namespace YesNt.Interpreter.Utilities;
-public static class StringExtentions
+public static class StringExtensions
{
private static readonly Dictionary reverseReplacementRules;
@@ -24,7 +24,7 @@ public static class StringExtentions
};
[SuppressMessage("Minor Code Smell", "S3963:\"static\" fields should be initialized inline", Justification = "Doesn't work because it throws a TypeInitializationException")]
- static StringExtentions()
+ static StringExtensions()
{
reverseReplacementRules = ReplacementRules.ToDictionary(x => x.Value, x => x.Key);
}
diff --git a/YesNt.Interpreter/YesNt.Interpreter.csproj b/YesNt.Interpreter/YesNt.Interpreter.csproj
index 3b71ea2..1093ec0 100644
--- a/YesNt.Interpreter/YesNt.Interpreter.csproj
+++ b/YesNt.Interpreter/YesNt.Interpreter.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net8.0
YesNt.Interpreter
Exe
From c3bc324519ab55e4b949ab01dabbfae130529d46 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 7 Aug 2024 20:17:59 +0200
Subject: [PATCH 15/73] Reset function in and out parameters stack
---
YesNt.Interpreter/Runtime/RuntimeInformation.cs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/YesNt.Interpreter/Runtime/RuntimeInformation.cs b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
index 0eb4676..719e010 100644
--- a/YesNt.Interpreter/Runtime/RuntimeInformation.cs
+++ b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
@@ -153,6 +153,8 @@ internal sealed class RuntimeInformation
Labels.Clear();
Functions.Clear();
FunctionCallStack.Clear();
+ InParametersStack.Clear();
+ OutParametersStack.Clear();
ParentRuntimeInformation = null;
SearchLabel = string.Empty;
SearchFunction = string.Empty;
From 7e357884f53b31076526c68bc964215268fc9491 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 7 Aug 2024 21:19:45 +0200
Subject: [PATCH 16/73] `get` and `out` statements can now be placed anywhere
and function arguments are now always in correct order
---
.../Statements/CodeFlowStatements.cs | 3 +-
.../Statements/FunctionStatements.cs | 49 +++++++++----------
2 files changed, 23 insertions(+), 29 deletions(-)
diff --git a/YesNt.Interpreter/Statements/CodeFlowStatements.cs b/YesNt.Interpreter/Statements/CodeFlowStatements.cs
index d1ccdd6..7ae96a9 100644
--- a/YesNt.Interpreter/Statements/CodeFlowStatements.cs
+++ b/YesNt.Interpreter/Statements/CodeFlowStatements.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using YesNt.Interpreter.Attributes;
using YesNt.Interpreter.Enums;
@@ -89,7 +88,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
{
string key = args.Trim();
- RuntimeInfo.FunctionCallStack.Push(new FunctionScope(RuntimeInfo.LineNumber, new Stack(RuntimeInfo.InParametersStack.Reverse())));
+ RuntimeInfo.FunctionCallStack.Push(new FunctionScope(RuntimeInfo.LineNumber, new Stack(RuntimeInfo.InParametersStack)));
RuntimeInfo.InParametersStack.Clear();
if (RuntimeInfo.Functions.TryGetValue(key, out int value))
diff --git a/YesNt.Interpreter/Statements/FunctionStatements.cs b/YesNt.Interpreter/Statements/FunctionStatements.cs
index de923c2..4fef510 100644
--- a/YesNt.Interpreter/Statements/FunctionStatements.cs
+++ b/YesNt.Interpreter/Statements/FunctionStatements.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using YesNt.Interpreter.Attributes;
using YesNt.Interpreter.Enums;
using YesNt.Interpreter.Runtime;
+using YesNt.Interpreter.Utilities;
namespace YesNt.Interpreter.Statements;
@@ -42,29 +43,26 @@ internal class FunctionStatements : StatementRuntimeInformation
RuntimeInfo.InParametersStack.Push(args);
}
- [Statement("out", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
+ [Statement("%out", SearchMode.Contains, SpaceAround.None, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void GetOutParameter(string args)
{
- if (RuntimeInfo.OutParametersStack.Count == 0)
+ while (args.Contains("%out"))
{
- RuntimeInfo.Exit("No out argument in stack", true);
- return;
+ if (RuntimeInfo.OutParametersStack.Count == 0)
+ {
+ RuntimeInfo.Exit("No out argument in stack", true);
+ return;
+ }
+
+ args = args.ReplaceFirstOccurrence("%out", RuntimeInfo.OutParametersStack.Pop());
}
- if (RuntimeInfo.Variables.ContainsKey(args))
- {
- RuntimeInfo.Variables[args] = RuntimeInfo.OutParametersStack.Pop();
- }
- else
- {
- RuntimeInfo.Variables.Add(args, RuntimeInfo.OutParametersStack.Pop());
- }
+ RuntimeInfo.CurrentLine = args.TrimEnd();
}
[Statement("%iso", SearchMode.Contains, SpaceAround.None, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void CheckIfOutParameterAvailable(string args)
{
- args += " ";
args = args.Replace("%iso", (RuntimeInfo.OutParametersStack.Count > 0).ToString());
RuntimeInfo.CurrentLine = args.TrimEnd();
@@ -102,7 +100,7 @@ internal class FunctionStatements : StatementRuntimeInformation
}
}
- [Statement("get", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
+ [Statement("%get", SearchMode.Contains, SpaceAround.None, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void GetInParameter(string args)
{
if (!RuntimeInfo.IsInFunction)
@@ -111,23 +109,21 @@ internal class FunctionStatements : StatementRuntimeInformation
return;
}
- if (RuntimeInfo.FunctionCallStack.Peek().Arguments.Count == 0)
+ while (args.Contains("%get"))
{
- RuntimeInfo.Exit("No in argument in stack", true);
- return;
+ if (RuntimeInfo.FunctionCallStack.Peek().Arguments.Count == 0)
+ {
+ RuntimeInfo.Exit("No in argument in stack", true);
+ return;
+ }
+
+ args = args.ReplaceFirstOccurrence("%get", RuntimeInfo.FunctionCallStack.Peek().Arguments.Pop());
}
- if (RuntimeInfo.Variables.ContainsKey(args))
- {
- RuntimeInfo.Variables[args] = RuntimeInfo.FunctionCallStack.Peek().Arguments.Pop();
- }
- else
- {
- RuntimeInfo.Variables.Add(args, RuntimeInfo.FunctionCallStack.Peek().Arguments.Pop());
- }
+ RuntimeInfo.CurrentLine = args.TrimEnd();
}
- [Statement("%isi", SearchMode.Contains, SpaceAround.End, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ [Statement("%isi", SearchMode.Contains, SpaceAround.None, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void CheckIfInParameterAvailable(string args)
{
if (!RuntimeInfo.IsInFunction)
@@ -136,7 +132,6 @@ internal class FunctionStatements : StatementRuntimeInformation
return;
}
- args += " ";
args = args.Replace("%isi", (RuntimeInfo.FunctionCallStack.Peek().Arguments.Count > 0).ToString());
RuntimeInfo.CurrentLine = args.TrimEnd();
From cf274e1db9b5f6895ed9eb91f643bef8fe8e7680 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 7 Aug 2024 23:31:19 +0200
Subject: [PATCH 17/73] Add more escape codes
---
.../Utilities/StringExtentions.cs | 50 +++++++++++--------
1 file changed, 29 insertions(+), 21 deletions(-)
diff --git a/YesNt.Interpreter/Utilities/StringExtentions.cs b/YesNt.Interpreter/Utilities/StringExtentions.cs
index 0feb116..49d00f9 100644
--- a/YesNt.Interpreter/Utilities/StringExtentions.cs
+++ b/YesNt.Interpreter/Utilities/StringExtentions.cs
@@ -20,7 +20,14 @@ public static class StringExtensions
{">", "~grt" },
{",", "~com" },
{"!", "~exm" },
- {"|", "~pip" }
+ {"|", "~pip" },
+ {"\n","~nli" },
+ {"\r","~ret" },
+ {"\t","~tab" },
+ {"\b","~bac" },
+ {"\f","~for" },
+ {"\a","~ale" },
+ {"", "~emp" },
};
[SuppressMessage("Minor Code Smell", "S3963:\"static\" fields should be initialized inline", Justification = "Doesn't work because it throws a TypeInitializationException")]
@@ -42,26 +49,7 @@ public static class StringExtensions
public static string FromSafeString(this string input)
{
- return ReplaceOnce(input.Replace("\v", ""), reverseReplacementRules);
- }
-
- public static string ReplaceOnce(string input, Dictionary replacementRules)
- {
- IEnumerable> matches = replacementRules.Where(rule => input.Contains(rule.Key));
- if (!matches.Any())
- {
- return input;
- }
-
- KeyValuePair match = matches.First();
- int startIndex = input.IndexOf(match.Key);
- int endIndex = startIndex + match.Key.Length;
-
- string before = ReplaceOnce(input[..startIndex], replacementRules);
- string replaced = match.Value;
- string after = ReplaceOnce(input[endIndex..], replacementRules);
-
- return before + replaced + after;
+ return ReplaceOnce(input.Replace("\v", string.Empty), reverseReplacementRules);
}
public static bool ToStandardizedNumber(this string input, out double result)
@@ -92,4 +80,24 @@ public static class StringExtensions
return count;
}
+
+ private static string ReplaceOnce(string input, Dictionary replacementRules)
+ {
+ // ~emp/string.Empty is a special case, it is used to represent empty strings and won't work with the normal rules because an empty string always matches and causes an infinite loop 3 letter abbreviation
+ IEnumerable> matches = replacementRules.Where(rule => rule.Key != string.Empty && input.Contains(rule.Key));
+ if (!matches.Any())
+ {
+ return input;
+ }
+
+ KeyValuePair match = matches.First();
+ int startIndex = input.IndexOf(match.Key);
+ int endIndex = startIndex + match.Key.Length;
+
+ string before = ReplaceOnce(input[..startIndex], replacementRules);
+ string replaced = match.Value;
+ string after = ReplaceOnce(input[endIndex..], replacementRules);
+
+ return before + replaced + after;
+ }
}
\ No newline at end of file
From ec2f29479628cb5b8f6b721073ddb007482c4624 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 7 Aug 2024 23:31:53 +0200
Subject: [PATCH 18/73] Fix exec statement and syntax highlighter
---
YesNt.CodeEditor/SyntaxHighlighter.cs | 10 ++--
.../Statements/SystemStatements.cs | 52 ++++++++++---------
2 files changed, 33 insertions(+), 29 deletions(-)
diff --git a/YesNt.CodeEditor/SyntaxHighlighter.cs b/YesNt.CodeEditor/SyntaxHighlighter.cs
index 12c664e..5aaf33f 100644
--- a/YesNt.CodeEditor/SyntaxHighlighter.cs
+++ b/YesNt.CodeEditor/SyntaxHighlighter.cs
@@ -134,7 +134,7 @@ internal partial class SyntaxHighlighter(ReadOnlyCollection= 0 && colorIndex < 16)
{
- messagePart = Base64Decode(messagePart.Replace($"\r{stringColor}\r", string.Empty));
+ messagePart = Base64Decode(messagePart.Replace($"\v{stringColor}\v", string.Empty));
consoleColor = (ConsoleColor)colorIndex;
}
else
@@ -160,9 +160,9 @@ internal partial class SyntaxHighlighter(ReadOnlyCollection originalString.ReplaceFirstOccurrence(value, $"\0\r{(int)color}\r{base64Value}\0" + new string(' ', spacesAtEnd)),
- SearchMode.EndOfLine => originalString.ReplaceLastOccurrence(value, $"\0\r{(int)color}\r{base64Value}\0" + new string(' ', spacesAtEnd)),
- _ => originalString.Replace(value, $"\0\r{(int)color}\r{base64Value}\0" + new string(' ', spacesAtEnd))
+ SearchMode.StartOfLine => originalString.ReplaceFirstOccurrence(value, $"\0\v{(int)color}\v{base64Value}\0" + new string(' ', spacesAtEnd)),
+ SearchMode.EndOfLine => originalString.ReplaceLastOccurrence(value, $"\0\v{(int)color}\v{base64Value}\0" + new string(' ', spacesAtEnd)),
+ _ => originalString.Replace(value, $"\0\v{(int)color}\v{base64Value}\0" + new string(' ', spacesAtEnd))
};
return result;
}
@@ -176,6 +176,6 @@ internal partial class SyntaxHighlighter(ReadOnlyCollection[a-zA-Z0-9]+")]
private static partial Regex VariableRegex();
- [GeneratedRegex("(?<=(\\r))(.*)(?=\\r)")]
+ [GeneratedRegex("(?<=(\\v))(.*)(?=\\v)")]
private static partial Regex StringColorRegex();
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Statements/SystemStatements.cs b/YesNt.Interpreter/Statements/SystemStatements.cs
index c8d1e32..c5b603a 100644
--- a/YesNt.Interpreter/Statements/SystemStatements.cs
+++ b/YesNt.Interpreter/Statements/SystemStatements.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
@@ -60,10 +61,34 @@ internal class SystemStatements : StatementRuntimeInformation
}
}
+ private static void Process_ErrorDataReceived(Utilities.DataReceivedEventArgs e, Stack outputStack)
+ {
+ if (string.IsNullOrWhiteSpace(e.Data))
+ {
+ return;
+ }
+
+ outputStack.Push(e.Data.ToSafeString());
+ Console.Write("Error: " + e.Data);
+ }
+
+ private static void Process_OutputDataReceived(Utilities.DataReceivedEventArgs e, Stack outputStack)
+ {
+ if (string.IsNullOrWhiteSpace(e.Data))
+ {
+ return;
+ }
+
+ outputStack.Push(e.Data.ToSafeString());
+ Console.Write(e.Data);
+ }
+
private void StartProcess(string name, string args)
{
RuntimeInfo.OutParametersStack.Clear();
+ Stack outputStack = new Stack();
+
FixedProcess process = new FixedProcess
{
StartInfo = new ProcessStartInfo()
@@ -75,8 +100,8 @@ internal class SystemStatements : StatementRuntimeInformation
}
};
- process.OutputDataReceived += Process_OutputDataReceived;
- process.ErrorDataReceived += Process_ErrorDataReceived;
+ process.OutputDataReceived += (s, e) => Process_OutputDataReceived(e, outputStack);
+ process.ErrorDataReceived += (s, e) => Process_ErrorDataReceived(e, outputStack);
_ = process.Start();
process.BeginOutputReadLine();
@@ -85,28 +110,7 @@ internal class SystemStatements : StatementRuntimeInformation
RuntimeInfo.InParametersStack.Clear();
+ RuntimeInfo.OutParametersStack = new(outputStack);
RuntimeInfo.OutParametersStack.Push(process.ExitCode.ToString());
}
-
- private void Process_ErrorDataReceived(object sender, Utilities.DataReceivedEventArgs e)
- {
- if (string.IsNullOrWhiteSpace(e.Data))
- {
- return;
- }
-
- RuntimeInfo.OutParametersStack.Push(e.Data);
- Console.Write("Error: " + e.Data);
- }
-
- private void Process_OutputDataReceived(object sender, Utilities.DataReceivedEventArgs e)
- {
- if (string.IsNullOrWhiteSpace(e.Data))
- {
- return;
- }
-
- RuntimeInfo.OutParametersStack.Push(e.Data);
- Console.Write(e.Data);
- }
}
\ No newline at end of file
From 9a6f1d780608480fc4eae089e6c3fd4b1660c008 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Thu, 8 Aug 2024 23:57:40 +0200
Subject: [PATCH 19/73] Escape invisible character is debug mode
---
YesNt.CodeEditor/Editor.cs | 11 +++--
YesNt.CodeEditor/YesNt.CodeEditor.csproj | 4 ++
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 8 +--
.../Statements/ConsoleStatements.cs | 2 +-
.../Statements/ProcessingStatements.cs | 2 +-
.../Utilities/ConsoleExtentions.cs | 49 +++++++++----------
6 files changed, 42 insertions(+), 34 deletions(-)
diff --git a/YesNt.CodeEditor/Editor.cs b/YesNt.CodeEditor/Editor.cs
index 11e1eb5..f3f7698 100644
--- a/YesNt.CodeEditor/Editor.cs
+++ b/YesNt.CodeEditor/Editor.cs
@@ -203,12 +203,17 @@ internal class TextEditor
return padding;
}
+ private static string ToLiteral(string input)
+ {
+ return Microsoft.CodeAnalysis.CSharp.SymbolDisplay.FormatLiteral(input, false);
+ }
+
private void YesNtInterpreter_OnDebugOutput(string output)
{
debugOutput.Add(output);
}
- private void YesNtInterpreter_OnLineExecuted(Interpreter.Runtime.DebugEventArgs e)
+ private void YesNtInterpreter_OnLineExecuted(DebugEventArgs e)
{
lock (Console.Out)
{
@@ -221,11 +226,11 @@ internal class TextEditor
if (e.OriginalLine == e.CurrentLine)
{
- Console.WriteLine($"{sharedString}[{e.CurrentLine}] ==>");
+ Console.WriteLine($"{sharedString}[{ToLiteral(e.CurrentLine)}] ==>");
}
else
{
- Console.WriteLine($"{sharedString}[{e.OriginalLine}] => [{e.CurrentLine}] ==>");
+ Console.WriteLine($"{sharedString}[{ToLiteral(e.OriginalLine)}] => [{ToLiteral(e.CurrentLine)}] ==>");
}
Console.ForegroundColor = ConsoleColor.Gray;
}
diff --git a/YesNt.CodeEditor/YesNt.CodeEditor.csproj b/YesNt.CodeEditor/YesNt.CodeEditor.csproj
index b7ba18b..5b45dec 100644
--- a/YesNt.CodeEditor/YesNt.CodeEditor.csproj
+++ b/YesNt.CodeEditor/YesNt.CodeEditor.csproj
@@ -10,6 +10,10 @@
+
+
+
+
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index fdfd80d..0559a7c 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -52,20 +52,20 @@ public class YesNtInterpreter
Assembly assembly = Assembly.GetExecutingAssembly();
Type[] types = assembly.GetTypes();
- IEnumerable statementRuntimeInfos = types.Where(t => t.IsSubclassOf(typeof(StatementRuntimeInformation)));
+ IEnumerable allStatementRuntimeInfo = types.Where(t => t.IsSubclassOf(typeof(StatementRuntimeInformation)));
statements.Clear();
- foreach (Type type in statementRuntimeInfos)
+ foreach (Type type in allStatementRuntimeInfo)
{
object statementInfo = Activator.CreateInstance(type);
- MethodInfo[] methodInfos = statementInfo.GetType().GetMethods();
+ MethodInfo[] allMethodInfo = statementInfo.GetType().GetMethods();
StatementRuntimeInformation statementRuntimeInfo = statementInfo as StatementRuntimeInformation;
statementRuntimeInfo.RuntimeInfo = runtimeInfo;
- foreach (MethodInfo methodInfo in methodInfos)
+ foreach (MethodInfo methodInfo in allMethodInfo)
{
StatementAttribute statementAttribute = methodInfo.GetCustomAttribute();
if (statementAttribute is not null)
diff --git a/YesNt.Interpreter/Statements/ConsoleStatements.cs b/YesNt.Interpreter/Statements/ConsoleStatements.cs
index 406db42..b7f1fdb 100644
--- a/YesNt.Interpreter/Statements/ConsoleStatements.cs
+++ b/YesNt.Interpreter/Statements/ConsoleStatements.cs
@@ -51,7 +51,7 @@ internal class ConsoleStatements : StatementRuntimeInformation
args += " ";
while (args.Contains("%cr"))
{
- string input = ConsoleExtentions.ReadKey(RuntimeInfo).ToString();
+ string input = ConsoleExtensions.ReadKey(RuntimeInfo).ToString();
args = args.ReplaceFirstOccurrence("%cr ", input.ToSafeString() + " ");
}
RuntimeInfo.CurrentLine = args.TrimEnd();
diff --git a/YesNt.Interpreter/Statements/ProcessingStatements.cs b/YesNt.Interpreter/Statements/ProcessingStatements.cs
index e606aea..60af01f 100644
--- a/YesNt.Interpreter/Statements/ProcessingStatements.cs
+++ b/YesNt.Interpreter/Statements/ProcessingStatements.cs
@@ -62,7 +62,7 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
{
if (int.TryParse(args, out int millisecondsTimeout))
{
- ConsoleExtentions.Sleep(millisecondsTimeout, RuntimeInfo);
+ ConsoleExtensions.Sleep(millisecondsTimeout, RuntimeInfo);
}
else
{
diff --git a/YesNt.Interpreter/Utilities/ConsoleExtentions.cs b/YesNt.Interpreter/Utilities/ConsoleExtentions.cs
index a394935..f401e52 100644
--- a/YesNt.Interpreter/Utilities/ConsoleExtentions.cs
+++ b/YesNt.Interpreter/Utilities/ConsoleExtentions.cs
@@ -4,35 +4,34 @@ using System.Threading;
using YesNt.Interpreter.Runtime;
-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 ' ';
- }
+namespace YesNt.Interpreter.Utilities;
- public static void Sleep(int millisecondsTimeout, RuntimeInformation runtimeInformation)
+internal static class ConsoleExtensions
+{
+ public static char ReadKey(RuntimeInformation runtimeInformation)
+ {
+ while (!runtimeInformation.Stop)
{
- Stopwatch stopwatch = new Stopwatch();
- stopwatch.Start();
- while (!runtimeInformation.Stop)
+ if (Console.KeyAvailable)
{
- if (stopwatch.ElapsedMilliseconds > millisecondsTimeout)
- {
- return;
- }
- Thread.Sleep(10);
+ 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);
}
}
}
\ No newline at end of file
From 1df0d348415c28632cfeececa133b44e8ccafa6a Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Thu, 8 Aug 2024 23:57:55 +0200
Subject: [PATCH 20/73] Add more unit test
---
...eFowTests.cs => CodeFowStatementsTests.cs} | 6 ---
.../ProcessingStatementsTests.cs | 43 +++++++++++++++++++
2 files changed, 43 insertions(+), 6 deletions(-)
rename YesNt.Interpreter.Tests/{CodeFowTests.cs => CodeFowStatementsTests.cs} (84%)
create mode 100644 YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
diff --git a/YesNt.Interpreter.Tests/CodeFowTests.cs b/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
similarity index 84%
rename from YesNt.Interpreter.Tests/CodeFowTests.cs
rename to YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
index 66444e5..8944543 100644
--- a/YesNt.Interpreter.Tests/CodeFowTests.cs
+++ b/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
@@ -34,10 +34,4 @@ public class CodeFlowTests
];
YesNtAssert.IsLastLineEqual(lines, "1");
}
-
- [TestMethod]
- public void CalculationsTest()
- {
- YesNtAssert.IsLineEqual("10 * 10 !calc", 100.ToString());
- }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs b/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
new file mode 100644
index 0000000..e445b55
--- /dev/null
+++ b/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
@@ -0,0 +1,43 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace YesNt.Interpreter.Tests;
+
+[TestClass]
+public class ProcessingStatementsTests
+{
+ [TestMethod]
+ public void MultiplicationTest()
+ {
+ YesNtAssert.IsLineEqual("10 * 10 !calc", "100");
+ }
+
+ [TestMethod]
+ public void DivisionTest()
+ {
+ YesNtAssert.IsLineEqual("90 / 4 !calc", "22.5");
+ }
+
+ [TestMethod]
+ public void AdditionTest()
+ {
+ YesNtAssert.IsLineEqual("10 + 10 !calc", "20");
+ }
+
+ [TestMethod]
+ public void SubtractionTest()
+ {
+ YesNtAssert.IsLineEqual("10 - 10 !calc", "0");
+ }
+
+ [TestMethod]
+ public void ModulusTest()
+ {
+ YesNtAssert.IsLineEqual("10 % 3 !calc", "1");
+ }
+
+ [TestMethod]
+ public void ExponentiationTest()
+ {
+ YesNtAssert.IsLineEqual("2 ^ 3 !calc", "8");
+ }
+}
\ No newline at end of file
From 11200cbff872c6d35d2c0bb510f487b01bc81036 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Tue, 4 Mar 2025 15:14:01 +0100
Subject: [PATCH 21/73] Don't throw exception when line that contains >
contains no variable found
---
YesNt.Interpreter/Statements/VariableStatements.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/YesNt.Interpreter/Statements/VariableStatements.cs b/YesNt.Interpreter/Statements/VariableStatements.cs
index dba0c93..21ea74c 100644
--- a/YesNt.Interpreter/Statements/VariableStatements.cs
+++ b/YesNt.Interpreter/Statements/VariableStatements.cs
@@ -93,7 +93,7 @@ internal partial class VariableStatements : StatementRuntimeInformation
if (matches.Count <= 0)
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ return;
}
for (int i = 0; i < matches.Count; i++)
From 9d43f1373f903cd3961864ce317e3e9fe7edb0c9 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 14:04:00 +0100
Subject: [PATCH 22/73] Make syntax more readable
---
README.md | 17 +++-
SYNTAX_V2.md | 93 +++++++++++++++++++
YesNt.CodeEditor/SyntaxHighlighter.cs | 8 +-
.../CodeFowStatementsTests.cs | 22 ++---
.../ProcessingStatementsTests.cs | 14 +--
.../Statements/CodeFlowStatements.cs | 43 +++++----
.../Statements/ConsoleStatements.cs | 22 ++---
.../Statements/FunctionStatements.cs | 39 ++++----
.../PredifinedVariableStatements.cs | 8 +-
.../Statements/ProcessingStatements.cs | 14 +--
.../Statements/SystemStatements.cs | 14 +--
.../Statements/VariableStatements.cs | 20 ++--
12 files changed, 216 insertions(+), 98 deletions(-)
create mode 100644 SYNTAX_V2.md
diff --git a/README.md b/README.md
index e840c92..5a83f33 100644
--- a/README.md
+++ b/README.md
@@ -2,4 +2,19 @@
> YesNt is a imperative and interpreted language inspired by the Assembly language.
-Check out the [Wiki](https://github.com/Stone-Red-Code/YesNt-Interpreter/wiki) (Work in progress)
+## Syntax
+
+Current language syntax is documented in [SYNTAX_V2.md](SYNTAX_V2.md).
+
+Example:
+
+```ynt
+let name = world
+print_line Hello ${name}
+```
+
+## Run
+
+```bash
+dotnet run --project YesNt.Interpreter -- path/to/script.ynt
+```
diff --git a/SYNTAX_V2.md b/SYNTAX_V2.md
new file mode 100644
index 0000000..ff18b42
--- /dev/null
+++ b/SYNTAX_V2.md
@@ -0,0 +1,93 @@
+# YesNt v2 Syntax
+
+This document describes the current, word-based YesNt syntax.
+
+## Goals
+
+- Keep current semantics and execution model.
+- Replace terse mnemonics and symbols with readable words.
+- Preserve line-based scripting.
+- Keep the language line-based and lightweight.
+
+## v2 Core Rules
+
+- Statements are line-based.
+- `# ...` remains a comment.
+- Variable interpolation inside text uses `${name}`.
+- Function and label declarations are block markers with a trailing `:`.
+- Conditions retain current evaluator expressions (for example: `a == b`, `x > 5`, `10 + 2 == 12`).
+
+## Quick Example
+
+v1:
+
+```ynt
+name
+ret
+cal greet
+```
+
+v2:
+
+```ynt
+let name = world
+func greet:
+print_line Hello ${name}
+return
+call greet
+```
+
+## Full v1 -> v2 Mapping
+
+| Area | v1 Syntax | v2 Syntax | Notes |
+|---|---|---|---|
+| Variables | `x` | `${x}` | Variable read/interpolation token. |
+| Console | `cwl` | `print_line` | Empty line print. |
+| Console | `cwl text` | `print_line text` | Print with newline. |
+| Console | `cw text` | `print text` | Print without newline. |
+| Console | `%crl` | `%read_line` | Inline token, inserts user line input. |
+| Console | `%cr` | `%read_key` | Inline token, inserts user key input. |
+| Console | `cls` | `clear` | Clear console. |
+| Code flow | `lbl name` | `label name:` | Label declaration/target. |
+| Code flow | `jmp name` | `goto name` | Unconditional jump. |
+| Code flow | `jif name \| cond` | `if cond goto name` | Conditional jump. |
+| Functions | `fnc name` | `func name:` | Function declaration. |
+| Functions | `cal name` | `call name` | Function call without args. |
+| Functions | `cal name \| a,b,c` | `call name with a, b, c` | Function call with args. |
+| Functions | `in value` | `push_in value` | Push in-arg onto input stack. |
+| Functions | `%get` | `%in` | Inline token, pop current call input arg. |
+| Functions | `%isi` | `%has_in` | Inline token, bool if input arg exists. |
+| Functions | `put value` | `push_out value` | Push out-arg in function. |
+| Functions | `%out` | `%out` | Keep token name for familiarity. |
+| Functions | `%iso` | `%has_out` | Inline token, bool if out arg exists. |
+| Functions | `ret` | `return` | Return from function. |
+| Functions | `ccs` | `clear_call_stack` | Clear call stack. |
+| Condition-call | `cif name \| cond` | `if cond call name` | Conditional function call. |
+| Termination | `end` | `exit` | Planned termination. |
+| Termination | `trm` | `abort_all` | Planned termination + cancel tasks. |
+| Errors | `trw message` | `throw message` | Error termination. |
+| Errors | `err message` | `error message` | Non-fatal/runtime message end state. |
+| Processing | `expr !calc` | `expr calc` | Evaluate arithmetic fragments. |
+| Processing | `text !eval` | `text eval` | Decode safe string literals. |
+| Processing | `line !task` | `line task` | Run line in background task runtime. |
+| Processing | `slp ms` | `sleep ms` | Sleep with runtime-aware cancellation. |
+| Processing | `len text` | `length text` | Push text length to out stack. |
+| Processing | `imp file` | `import file` | Inline include of another `.ynt` file. |
+| System | `exc prog` | `exec prog` | Execute process with in-stack args. |
+| System | `exc prog \| a,b,c` | `exec prog with a, b, c` | Execute process with explicit args. |
+| Predefined | `%time` | `%time` | Unix timestamp token. |
+| Predefined | `%os` | `%os` | OS platform token. |
+| Predefined | `%cpu` | `%cpu` | Processor architecture token. |
+| Predefined | `%is64` | `%is64` | 64-bit OS bool token. |
+| Predefined | `%pi` | `%pi` | PI token. |
+| Predefined | `%rnd` | `%rand` | Random number token. |
+
+## Notes
+
+- `%out` is intentionally kept as `%out`.
+- Postfix operations are `calc`, `eval`, and `task`.
diff --git a/YesNt.CodeEditor/SyntaxHighlighter.cs b/YesNt.CodeEditor/SyntaxHighlighter.cs
index 5aaf33f..a368796 100644
--- a/YesNt.CodeEditor/SyntaxHighlighter.cs
+++ b/YesNt.CodeEditor/SyntaxHighlighter.cs
@@ -167,15 +167,15 @@ internal partial class SyntaxHighlighter(ReadOnlyCollection[a-zA-Z0-9]+")]
+ [GeneratedRegex("\\$\\{[a-zA-Z0-9]+\\}")]
private static partial Regex VariableRegex();
[GeneratedRegex("(?<=(\\v))(.*)(?=\\v)")]
private static partial Regex StringColorRegex();
-}
\ No newline at end of file
+}
diff --git a/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs b/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
index 8944543..0bddd5b 100644
--- a/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
@@ -12,11 +12,11 @@ public class CodeFlowTests
{
List lines =
[
- "cal yes",
- "fnc yes",
- "!result"
+ "call yes",
+ "func yes:",
+ "global result = 1",
+ "return",
+ "${result}"
];
YesNtAssert.IsLastLineEqual(lines, "1");
}
@@ -26,12 +26,12 @@ public class CodeFlowTests
{
List lines =
[
- "result"
+ "let result = 1",
+ "goto yes",
+ "let result = 0",
+ "label yes:",
+ "${result}"
];
YesNtAssert.IsLastLineEqual(lines, "1");
}
-}
\ No newline at end of file
+}
diff --git a/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs b/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
index e445b55..fd68646 100644
--- a/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
@@ -8,36 +8,36 @@ public class ProcessingStatementsTests
[TestMethod]
public void MultiplicationTest()
{
- YesNtAssert.IsLineEqual("10 * 10 !calc", "100");
+ YesNtAssert.IsLineEqual("10 * 10 calc", "100");
}
[TestMethod]
public void DivisionTest()
{
- YesNtAssert.IsLineEqual("90 / 4 !calc", "22.5");
+ YesNtAssert.IsLineEqual("90 / 4 calc", "22.5");
}
[TestMethod]
public void AdditionTest()
{
- YesNtAssert.IsLineEqual("10 + 10 !calc", "20");
+ YesNtAssert.IsLineEqual("10 + 10 calc", "20");
}
[TestMethod]
public void SubtractionTest()
{
- YesNtAssert.IsLineEqual("10 - 10 !calc", "0");
+ YesNtAssert.IsLineEqual("10 - 10 calc", "0");
}
[TestMethod]
public void ModulusTest()
{
- YesNtAssert.IsLineEqual("10 % 3 !calc", "1");
+ YesNtAssert.IsLineEqual("10 % 3 calc", "1");
}
[TestMethod]
public void ExponentiationTest()
{
- YesNtAssert.IsLineEqual("2 ^ 3 !calc", "8");
+ YesNtAssert.IsLineEqual("2 ^ 3 calc", "8");
}
-}
\ No newline at end of file
+}
diff --git a/YesNt.Interpreter/Statements/CodeFlowStatements.cs b/YesNt.Interpreter/Statements/CodeFlowStatements.cs
index 7ae96a9..91fc087 100644
--- a/YesNt.Interpreter/Statements/CodeFlowStatements.cs
+++ b/YesNt.Interpreter/Statements/CodeFlowStatements.cs
@@ -10,10 +10,10 @@ namespace YesNt.Interpreter.Statements;
internal class CodeFlowStatements : StatementRuntimeInformation
{
- [Statement("jmp", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow)]
+ [Statement("goto", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow)]
public void Jump(string args)
{
- string key = args.Trim();
+ string key = NormalizeBlockName(args);
if (RuntimeInfo.Labels.TryGetValue(key, out int value))
{
@@ -26,18 +26,18 @@ internal class CodeFlowStatements : StatementRuntimeInformation
}
}
- [Statement("jif", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow, Separator = "|")]
+ [Statement("if", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow, Separator = " goto ")]
public void JumpIf(string args)
{
- string[] parts = args.Split('|');
+ string[] parts = args.Split(" goto ", 2, StringSplitOptions.None);
if (parts.Length != 2)
{
RuntimeInfo.Exit("Invalid syntax", true);
return;
}
- string key = parts[0].Trim();
- string condition = parts[1].Trim();
+ string condition = parts[0].Trim();
+ string key = NormalizeBlockName(parts[1]);
bool? result = Evaluator.EvaluateCondition(condition);
@@ -63,10 +63,10 @@ internal class CodeFlowStatements : StatementRuntimeInformation
}
}
- [Statement("lbl", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, ExecuteInSearchMode = true)]
+ [Statement("label", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, ExecuteInSearchMode = true)]
public void FindLabel(string args)
{
- string key = args.Trim();
+ string key = NormalizeBlockName(args);
if (RuntimeInfo.Labels.ContainsKey(key))
{
RuntimeInfo.Labels[key] = RuntimeInfo.LineNumber;
@@ -83,10 +83,10 @@ internal class CodeFlowStatements : StatementRuntimeInformation
}
}
- [Statement("cal", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, Priority = Priority.VeryLow)]
+ [Statement("call", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, Priority = Priority.VeryLow)]
public void Call(string args)
{
- string key = args.Trim();
+ string key = NormalizeBlockName(args);
RuntimeInfo.FunctionCallStack.Push(new FunctionScope(RuntimeInfo.LineNumber, new Stack(RuntimeInfo.InParametersStack)));
RuntimeInfo.InParametersStack.Clear();
@@ -101,18 +101,18 @@ internal class CodeFlowStatements : StatementRuntimeInformation
}
}
- [Statement("cif", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, Priority = Priority.VeryLow, Separator = "|")]
+ [Statement("if", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, Priority = Priority.VeryLow, Separator = " call ")]
public void CallIf(string args)
{
- string[] parts = args.Split('|');
+ string[] parts = args.Split(" call ", 2, StringSplitOptions.None);
if (parts.Length != 2)
{
RuntimeInfo.Exit("Invalid syntax", true);
return;
}
- string key = parts[0].Trim();
- string condition = parts[1].Trim();
+ string condition = parts[0].Trim();
+ string key = NormalizeBlockName(parts[1]);
bool? result = Evaluator.EvaluateCondition(condition);
@@ -140,7 +140,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
}
}
- [Statement("end", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red, ExecuteInSearchMode = true)]
+ [Statement("exit", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red, ExecuteInSearchMode = true)]
public void End(string _)
{
if (RuntimeInfo.IsSearching)
@@ -161,7 +161,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
RuntimeInfo.Exit("Planned termination by code", false);
}
- [Statement("trm", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red, ExecuteInSearchMode = true)]
+ [Statement("abort_all", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red, ExecuteInSearchMode = true)]
public void Terminate(string _)
{
if (RuntimeInfo.IsSearching)
@@ -182,15 +182,20 @@ internal class CodeFlowStatements : StatementRuntimeInformation
RuntimeInfo.Exit("Planned termination by code. Canceling all tasks", true);
}
- [Statement("trw", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Red)]
+ [Statement("throw", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Red)]
public void Throw(string message)
{
RuntimeInfo.Exit(message, true);
}
- [Statement("err", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Red)]
+ [Statement("error", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Red)]
public void Error(string message)
{
RuntimeInfo.Exit(message, false);
}
-}
\ No newline at end of file
+
+ private static string NormalizeBlockName(string value)
+ {
+ return value.Trim().TrimEnd(':').Trim();
+ }
+}
diff --git a/YesNt.Interpreter/Statements/ConsoleStatements.cs b/YesNt.Interpreter/Statements/ConsoleStatements.cs
index b7f1fdb..50264b4 100644
--- a/YesNt.Interpreter/Statements/ConsoleStatements.cs
+++ b/YesNt.Interpreter/Statements/ConsoleStatements.cs
@@ -10,29 +10,29 @@ namespace YesNt.Interpreter.Statements;
internal class ConsoleStatements : StatementRuntimeInformation
{
- [Statement("cwl", SearchMode.Exact, SpaceAround.None, ConsoleColor.DarkGreen, Priority = Priority.VeryLow)]
+ [Statement("print_line", SearchMode.Exact, SpaceAround.None, ConsoleColor.DarkGreen, Priority = Priority.VeryLow)]
public void WriteLineEmpty(string _)
{
RuntimeInfo.WriteLine(string.Empty);
}
- [Statement("cwl", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkGreen, Priority = Priority.VeryLow)]
+ [Statement("print_line", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkGreen, Priority = Priority.VeryLow)]
public void WriteLine(string args)
{
RuntimeInfo.WriteLine(args);
}
- [Statement("cw", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkGreen, Priority = Priority.VeryLow)]
+ [Statement("print", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkGreen, Priority = Priority.VeryLow)]
public void Write(string args)
{
RuntimeInfo.Write(args);
}
- [Statement("%crl", SearchMode.Contains, SpaceAround.None, ConsoleColor.DarkGreen, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ [Statement("%read_line", SearchMode.Contains, SpaceAround.None, ConsoleColor.DarkGreen, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void ReadLine(string args)
{
args += " ";
- while (args.Contains("%crl"))
+ while (args.Contains("%read_line"))
{
string input = Console.ReadLine();
if (input is null)
@@ -40,27 +40,27 @@ internal class ConsoleStatements : StatementRuntimeInformation
RuntimeInfo.Exit("Terminated by external process", true);
return;
}
- args = args.ReplaceFirstOccurrence("%crl ", input.ToSafeString() + " ");
+ args = args.ReplaceFirstOccurrence("%read_line ", input.ToSafeString() + " ");
}
RuntimeInfo.CurrentLine = args.TrimEnd();
}
- [Statement("%cr", SearchMode.Contains, SpaceAround.None, ConsoleColor.DarkGreen, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ [Statement("%read_key", SearchMode.Contains, SpaceAround.None, ConsoleColor.DarkGreen, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void ReadKey(string args)
{
args += " ";
- while (args.Contains("%cr"))
+ while (args.Contains("%read_key"))
{
string input = ConsoleExtensions.ReadKey(RuntimeInfo).ToString();
- args = args.ReplaceFirstOccurrence("%cr ", input.ToSafeString() + " ");
+ args = args.ReplaceFirstOccurrence("%read_key ", input.ToSafeString() + " ");
}
RuntimeInfo.CurrentLine = args.TrimEnd();
}
- [Statement("cls", SearchMode.Exact, SpaceAround.None, ConsoleColor.Magenta)]
+ [Statement("clear", SearchMode.Exact, SpaceAround.None, ConsoleColor.Magenta)]
[SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Won't work if static")]
public void Clear(string _)
{
Console.Clear();
}
-}
\ No newline at end of file
+}
diff --git a/YesNt.Interpreter/Statements/FunctionStatements.cs b/YesNt.Interpreter/Statements/FunctionStatements.cs
index 4fef510..7e50ec4 100644
--- a/YesNt.Interpreter/Statements/FunctionStatements.cs
+++ b/YesNt.Interpreter/Statements/FunctionStatements.cs
@@ -10,7 +10,7 @@ namespace YesNt.Interpreter.Statements;
internal class FunctionStatements : StatementRuntimeInformation
{
- [Statement("fnc", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
+ [Statement("func", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
public void FindFunction(string args)
{
if (RuntimeInfo.InternalIsInFunction)
@@ -19,7 +19,7 @@ internal class FunctionStatements : StatementRuntimeInformation
return;
}
- string key = args.Trim();
+ string key = NormalizeBlockName(args);
if (RuntimeInfo.Functions.ContainsKey(key))
{
RuntimeInfo.Functions[key] = RuntimeInfo.LineNumber;
@@ -37,7 +37,7 @@ internal class FunctionStatements : StatementRuntimeInformation
RuntimeInfo.IsInFunction = true;
}
- [Statement("in", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
+ [Statement("push_in", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
public void AddInParameter(string args)
{
RuntimeInfo.InParametersStack.Push(args);
@@ -60,25 +60,25 @@ internal class FunctionStatements : StatementRuntimeInformation
RuntimeInfo.CurrentLine = args.TrimEnd();
}
- [Statement("%iso", SearchMode.Contains, SpaceAround.None, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ [Statement("%has_out", SearchMode.Contains, SpaceAround.None, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void CheckIfOutParameterAvailable(string args)
{
- args = args.Replace("%iso", (RuntimeInfo.OutParametersStack.Count > 0).ToString());
+ args = args.Replace("%has_out", (RuntimeInfo.OutParametersStack.Count > 0).ToString());
RuntimeInfo.CurrentLine = args.TrimEnd();
}
- [Statement("cal", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, Priority = Priority.Low, Separator = "|")]
+ [Statement("call", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, Priority = Priority.Low, Separator = " with ")]
public void Call(string args)
{
- string[] parts = args.Split('|');
+ string[] parts = args.Split(" with ", 2, StringSplitOptions.None);
if (parts.Length != 2)
{
RuntimeInfo.Exit("Invalid syntax", true);
return;
}
- string key = parts[0].Trim();
+ string key = NormalizeBlockName(parts[0]);
string[] functionArguments = parts[1].Split(',');
foreach (string argument in functionArguments)
@@ -100,7 +100,7 @@ internal class FunctionStatements : StatementRuntimeInformation
}
}
- [Statement("%get", SearchMode.Contains, SpaceAround.None, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ [Statement("%in", SearchMode.Contains, SpaceAround.None, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void GetInParameter(string args)
{
if (!RuntimeInfo.IsInFunction)
@@ -109,7 +109,7 @@ internal class FunctionStatements : StatementRuntimeInformation
return;
}
- while (args.Contains("%get"))
+ while (args.Contains("%in"))
{
if (RuntimeInfo.FunctionCallStack.Peek().Arguments.Count == 0)
{
@@ -117,13 +117,13 @@ internal class FunctionStatements : StatementRuntimeInformation
return;
}
- args = args.ReplaceFirstOccurrence("%get", RuntimeInfo.FunctionCallStack.Peek().Arguments.Pop());
+ args = args.ReplaceFirstOccurrence("%in", RuntimeInfo.FunctionCallStack.Peek().Arguments.Pop());
}
RuntimeInfo.CurrentLine = args.TrimEnd();
}
- [Statement("%isi", SearchMode.Contains, SpaceAround.None, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ [Statement("%has_in", SearchMode.Contains, SpaceAround.None, ConsoleColor.Yellow, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void CheckIfInParameterAvailable(string args)
{
if (!RuntimeInfo.IsInFunction)
@@ -132,12 +132,12 @@ internal class FunctionStatements : StatementRuntimeInformation
return;
}
- args = args.Replace("%isi", (RuntimeInfo.FunctionCallStack.Peek().Arguments.Count > 0).ToString());
+ args = args.Replace("%has_in", (RuntimeInfo.FunctionCallStack.Peek().Arguments.Count > 0).ToString());
RuntimeInfo.CurrentLine = args.TrimEnd();
}
- [Statement("put", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
+ [Statement("push_out", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
public void AddOutParameter(string args)
{
if (!RuntimeInfo.IsInFunction)
@@ -149,7 +149,7 @@ internal class FunctionStatements : StatementRuntimeInformation
RuntimeInfo.FunctionCallStack.Peek().Results.Push(args);
}
- [Statement("ret", SearchMode.Exact, SpaceAround.None, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
+ [Statement("return", SearchMode.Exact, SpaceAround.None, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
public void Return(string _)
{
if (!RuntimeInfo.IsInFunction)
@@ -186,9 +186,14 @@ internal class FunctionStatements : StatementRuntimeInformation
}
}
- [Statement("ccs", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red)]
+ [Statement("clear_call_stack", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red)]
public void ClearCallStack(string _)
{
RuntimeInfo.FunctionCallStack.Clear();
}
-}
\ No newline at end of file
+
+ private static string NormalizeBlockName(string value)
+ {
+ return value.Trim().TrimEnd(':').Trim();
+ }
+}
diff --git a/YesNt.Interpreter/Statements/PredifinedVariableStatements.cs b/YesNt.Interpreter/Statements/PredifinedVariableStatements.cs
index e79276f..4036f94 100644
--- a/YesNt.Interpreter/Statements/PredifinedVariableStatements.cs
+++ b/YesNt.Interpreter/Statements/PredifinedVariableStatements.cs
@@ -51,14 +51,14 @@ internal class PredefinedVariableStatements : StatementRuntimeInformation
RuntimeInfo.CurrentLine = args.TrimEnd();
}
- [Statement("%rnd", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
+ [Statement("%rand", SearchMode.Contains, SpaceAround.None, ConsoleColor.Blue, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void GetRandom(string args)
{
- while (args.Contains("%rnd"))
+ while (args.Contains("%rand"))
{
- args = args.ReplaceFirstOccurrence("%rnd", random.Next(32767, int.MaxValue).ToString());
+ args = args.ReplaceFirstOccurrence("%rand", random.Next(32767, int.MaxValue).ToString());
}
RuntimeInfo.CurrentLine = args.TrimEnd();
}
-}
\ No newline at end of file
+}
diff --git a/YesNt.Interpreter/Statements/ProcessingStatements.cs b/YesNt.Interpreter/Statements/ProcessingStatements.cs
index 60af01f..aa1e963 100644
--- a/YesNt.Interpreter/Statements/ProcessingStatements.cs
+++ b/YesNt.Interpreter/Statements/ProcessingStatements.cs
@@ -13,7 +13,7 @@ namespace YesNt.Interpreter.Statements;
internal partial class ProcessingStatements : StatementRuntimeInformation
{
- [Statement("!calc", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.High)]
+ [Statement("calc", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.High)]
public void Calculate(string args)
{
MatchCollection matches = CalculationRegex().Matches(args.FromSafeString());
@@ -32,13 +32,13 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
RuntimeInfo.CurrentLine = args;
}
- [Statement("!eval", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.VeryHigh)]
+ [Statement("eval", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.VeryHigh)]
public void Evaluate(string args)
{
RuntimeInfo.CurrentLine = args.FromSafeString();
}
- [Statement("!task", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.VeryHigh)]
+ [Statement("task", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.VeryHigh)]
public void RunTask(string line)
{
int lineNumber = RuntimeInfo.LineNumber;
@@ -57,7 +57,7 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
RuntimeInfo.CurrentLine = string.Empty;
}
- [Statement("slp", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
+ [Statement("sleep", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
public void Sleep(string args)
{
if (int.TryParse(args, out int millisecondsTimeout))
@@ -70,7 +70,7 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
}
}
- [Statement("len", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
+ [Statement("length", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
public void Length(string args)
{
RuntimeInfo.InParametersStack.Clear();
@@ -79,7 +79,7 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
RuntimeInfo.OutParametersStack.Push(args.FromSafeString().Length.ToString());
}
- [Statement("imp", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
+ [Statement("import", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
public void Import(string path)
{
path = Path.Combine(RuntimeInfo.WorkingDirectory, path);
@@ -115,4 +115,4 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
[GeneratedRegex("[0-9*+().,^%/-]+[0-9*+ ().,^%/-]+[0-9*+().,^%/-]+")]
private static partial Regex CalculationRegex();
-}
\ No newline at end of file
+}
diff --git a/YesNt.Interpreter/Statements/SystemStatements.cs b/YesNt.Interpreter/Statements/SystemStatements.cs
index c5b603a..a5d148d 100644
--- a/YesNt.Interpreter/Statements/SystemStatements.cs
+++ b/YesNt.Interpreter/Statements/SystemStatements.cs
@@ -14,10 +14,10 @@ namespace YesNt.Interpreter.Statements;
internal class SystemStatements : StatementRuntimeInformation
{
- [Statement("exc", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta, Priority = Priority.Low, Separator = "|")]
+ [Statement("exec", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta, Priority = Priority.Low, Separator = " with ")]
public void ExecuteProgramWithArgs(string input)
{
- string[] parts = input.FromSafeString().Split('|');
+ string[] parts = input.FromSafeString().Split(" with ", 2, StringSplitOptions.None);
parts[0] = parts[0].Trim();
string[] functionArguments = parts[1].Split(',');
@@ -29,7 +29,7 @@ internal class SystemStatements : StatementRuntimeInformation
try
{
- StartProcess(parts[0], string.Join(string.Empty, RuntimeInfo.InParametersStack.Reverse()));
+ StartProcess(parts[0], string.Join(" ", RuntimeInfo.InParametersStack.Reverse()));
}
catch (FileNotFoundException)
{
@@ -40,16 +40,16 @@ internal class SystemStatements : StatementRuntimeInformation
RuntimeInfo.Exit($"Failed to start \"{parts[0]}\". {ex.Message}", false);
}
- //HACK: Clear line to avoid execution from other "exc" statement
+ // HACK: Clear line to avoid execution from another "exec" statement.
RuntimeInfo.CurrentLine = string.Empty;
}
- [Statement("exc", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta, Priority = Priority.VeryLow)]
+ [Statement("exec", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta, Priority = Priority.VeryLow)]
public void ExecuteProgram(string input)
{
try
{
- StartProcess(input, string.Join(string.Empty, RuntimeInfo.InParametersStack.Reverse()));
+ StartProcess(input, string.Join(" ", RuntimeInfo.InParametersStack.Reverse()));
}
catch (FileNotFoundException)
{
@@ -113,4 +113,4 @@ internal class SystemStatements : StatementRuntimeInformation
RuntimeInfo.OutParametersStack = new(outputStack);
RuntimeInfo.OutParametersStack.Push(process.ExitCode.ToString());
}
-}
\ No newline at end of file
+}
diff --git a/YesNt.Interpreter/Statements/VariableStatements.cs b/YesNt.Interpreter/Statements/VariableStatements.cs
index 21ea74c..9cfde6d 100644
--- a/YesNt.Interpreter/Statements/VariableStatements.cs
+++ b/YesNt.Interpreter/Statements/VariableStatements.cs
@@ -8,7 +8,7 @@ namespace YesNt.Interpreter.Statements;
internal partial class VariableStatements : StatementRuntimeInformation
{
- [Statement("<", SearchMode.StartOfLine, SpaceAround.None, Priority = Priority.VeryLow)]
+ [Statement("let", SearchMode.StartOfLine, SpaceAround.End, Priority = Priority.VeryLow)]
public void DefineVariable(string args)
{
string[] parts = args.Split('=');
@@ -35,7 +35,7 @@ internal partial class VariableStatements : StatementRuntimeInformation
}
}
- [Statement("!<", SearchMode.StartOfLine, SpaceAround.None, Priority = Priority.VeryLow)]
+ [Statement("global", SearchMode.StartOfLine, SpaceAround.End, Priority = Priority.VeryLow)]
public void DefineGlobalVariable(string args)
{
string[] parts = args.Split('=');
@@ -62,7 +62,7 @@ internal partial class VariableStatements : StatementRuntimeInformation
}
}
- [Statement("del", SearchMode.StartOfLine, SpaceAround.End, System.ConsoleColor.Red, Priority = Priority.VeryLow)]
+ [Statement("delete", SearchMode.StartOfLine, SpaceAround.End, System.ConsoleColor.Red, Priority = Priority.VeryLow)]
public void DeleteVariable(string args)
{
string key = args.Trim();
@@ -81,10 +81,10 @@ internal partial class VariableStatements : StatementRuntimeInformation
}
}
- [Statement(">", SearchMode.Contains, SpaceAround.None, Priority = Priority.Highest)]
+ [Statement("${", SearchMode.Contains, SpaceAround.None, Priority = Priority.Highest, Separator = "}")]
public void ReadVariable(string _)
{
- if (!RuntimeInfo.CurrentLine.Contains('>'))
+ if (!RuntimeInfo.CurrentLine.Contains("${"))
{
return;
}
@@ -98,14 +98,14 @@ internal partial class VariableStatements : StatementRuntimeInformation
for (int i = 0; i < matches.Count; i++)
{
- string varName = matches[i].Value.Replace(">", string.Empty);
+ string varName = matches[i].Groups[1].Value;
if (RuntimeInfo.Variables.TryGetValue(varName, out string value))
{
- RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{varName}", value);
+ RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace(matches[i].Value, value);
}
else if (RuntimeInfo.GlobalVariables.TryGetValue(varName, out value))
{
- RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{varName}", value);
+ RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace(matches[i].Value, value);
}
else if (!RuntimeInfo.IsSearching)
{
@@ -115,6 +115,6 @@ internal partial class VariableStatements : StatementRuntimeInformation
}
}
- [GeneratedRegex(">[a-zA-Z0-9]+")]
+ [GeneratedRegex("\\$\\{([a-zA-Z0-9]+)\\}")]
private static partial Regex VariableStatementRegex();
-}
\ No newline at end of file
+}
From 299558df70e6f1c851f9b2e094dad1511a3a3888 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 14:28:04 +0100
Subject: [PATCH 23/73] Add support for block-style if/else and while loop
statements with tests
---
SYNTAX_V2.md | 32 ++-
.../CodeFowStatementsTests.cs | 102 ++++++++
.../Statements/CodeFlowStatements.cs | 227 ++++++++++++++++++
3 files changed, 349 insertions(+), 12 deletions(-)
diff --git a/SYNTAX_V2.md b/SYNTAX_V2.md
index ff18b42..ab96d1d 100644
--- a/SYNTAX_V2.md
+++ b/SYNTAX_V2.md
@@ -19,18 +19,6 @@ This document describes the current, word-based YesNt syntax.
## Quick Example
-v1:
-
-```ynt
-name
-ret
-cal greet
-```
-
-v2:
-
```ynt
let name = world
func greet:
@@ -39,6 +27,26 @@ return
call greet
```
+## Block Conditionals
+
+```ynt
+if 10 > 5:
+print_line yes
+else:
+print_line no
+end_if
+```
+
+## While Loops
+
+```ynt
+let i = 3
+while ${i} > 0:
+print_line ${i}
+let i = ${i} - 1 calc
+end_while
+```
+
## Full v1 -> v2 Mapping
| Area | v1 Syntax | v2 Syntax | Notes |
diff --git a/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs b/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
index 0bddd5b..6bd75b9 100644
--- a/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
@@ -34,4 +34,106 @@ public class CodeFlowTests
];
YesNtAssert.IsLastLineEqual(lines, "1");
}
+
+ [TestMethod]
+ public void IfBlockTrueTest()
+ {
+ List lines =
+ [
+ "let result = low",
+ "if 6 > 5:",
+ "let result = high",
+ "end_if",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "high");
+ }
+
+ [TestMethod]
+ public void IfElseFalseBranchTest()
+ {
+ List lines =
+ [
+ "let result = low",
+ "if 6 < 5:",
+ "let result = high",
+ "else:",
+ "let result = medium",
+ "end_if",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "medium");
+ }
+
+ [TestMethod]
+ public void NestedIfElseTest()
+ {
+ List lines =
+ [
+ "let result = 0",
+ "if 1 == 1:",
+ "if 2 == 3:",
+ "let result = 1",
+ "else:",
+ "let result = 2",
+ "end_if",
+ "end_if",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "2");
+ }
+
+ [TestMethod]
+ public void WhileLoopTest()
+ {
+ List lines =
+ [
+ "let i = 3",
+ "while ${i} > 0:",
+ "let i = ${i} - 1 calc",
+ "end_while",
+ "${i}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "0");
+ }
+
+ [TestMethod]
+ public void WhileSkipBodyWhenFalseTest()
+ {
+ List lines =
+ [
+ "let i = 0",
+ "while ${i} > 0:",
+ "let i = 99",
+ "end_while",
+ "${i}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "0");
+ }
+
+ [TestMethod]
+ public void NestedWhileLoopTest()
+ {
+ List lines =
+ [
+ "let outer = 2",
+ "let count = 0",
+ "while ${outer} > 0:",
+ "let inner = 2",
+ "while ${inner} > 0:",
+ "let count = ${count} + 1 calc",
+ "let inner = ${inner} - 1 calc",
+ "end_while",
+ "let outer = ${outer} - 1 calc",
+ "end_while",
+ "${count}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "4");
+ }
}
diff --git a/YesNt.Interpreter/Statements/CodeFlowStatements.cs b/YesNt.Interpreter/Statements/CodeFlowStatements.cs
index 91fc087..38aee20 100644
--- a/YesNt.Interpreter/Statements/CodeFlowStatements.cs
+++ b/YesNt.Interpreter/Statements/CodeFlowStatements.cs
@@ -140,6 +140,105 @@ internal class CodeFlowStatements : StatementRuntimeInformation
}
}
+ [Statement("if", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow, Separator = ":")]
+ public void IfBlock(string args)
+ {
+ args = args.Trim();
+ if (!args.EndsWith(':'))
+ {
+ RuntimeInfo.Exit("Invalid syntax", true);
+ return;
+ }
+
+ string condition = args[..^1].Trim();
+ bool? result = Evaluator.EvaluateCondition(condition);
+
+ if (result is null)
+ {
+ RuntimeInfo.Exit("Invalid operation", true);
+ return;
+ }
+
+ if (result == true)
+ {
+ return;
+ }
+
+ (int targetLine, _) = FindElseOrEndIf(RuntimeInfo.LineNumber);
+ if (targetLine < 0)
+ {
+ RuntimeInfo.Exit("No matching end_if found", true);
+ return;
+ }
+
+ RuntimeInfo.LineNumber = targetLine;
+ }
+
+ [Statement("else:", SearchMode.Exact, SpaceAround.None, ConsoleColor.Green)]
+ public void Else(string _)
+ {
+ int targetLine = FindEndIf(RuntimeInfo.LineNumber);
+ if (targetLine < 0)
+ {
+ RuntimeInfo.Exit("No matching end_if found", true);
+ return;
+ }
+
+ RuntimeInfo.LineNumber = targetLine;
+ }
+
+ [Statement("end_if", SearchMode.Exact, SpaceAround.None, ConsoleColor.Green)]
+ public void EndIf(string _)
+ {
+ }
+
+ [Statement("while", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow, Separator = ":")]
+ public void While(string args)
+ {
+ args = args.Trim();
+ if (!args.EndsWith(':'))
+ {
+ RuntimeInfo.Exit("Invalid syntax", true);
+ return;
+ }
+
+ string condition = args[..^1].Trim();
+ bool? result = Evaluator.EvaluateCondition(condition);
+
+ if (result is null)
+ {
+ RuntimeInfo.Exit("Invalid operation", true);
+ return;
+ }
+
+ if (result == true)
+ {
+ return;
+ }
+
+ int endWhileLine = FindEndWhile(RuntimeInfo.LineNumber);
+ if (endWhileLine < 0)
+ {
+ RuntimeInfo.Exit("No matching end_while found", true);
+ return;
+ }
+
+ RuntimeInfo.LineNumber = endWhileLine;
+ }
+
+ [Statement("end_while", SearchMode.Exact, SpaceAround.None, ConsoleColor.Green)]
+ public void EndWhile(string _)
+ {
+ int whileLine = FindWhile(RuntimeInfo.LineNumber);
+ if (whileLine < 0)
+ {
+ RuntimeInfo.Exit("No matching while found", true);
+ return;
+ }
+
+ RuntimeInfo.LineNumber = whileLine - 1;
+ }
+
[Statement("exit", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red, ExecuteInSearchMode = true)]
public void End(string _)
{
@@ -198,4 +297,132 @@ internal class CodeFlowStatements : StatementRuntimeInformation
{
return value.Trim().TrimEnd(':').Trim();
}
+
+ private (int TargetLine, bool IsElse) FindElseOrEndIf(int currentLine)
+ {
+ int depth = 0;
+
+ for (int i = currentLine + 1; i < RuntimeInfo.Lines.Count; i++)
+ {
+ string line = RuntimeInfo.Lines[i].Content.Trim().Replace("\r", string.Empty);
+
+ if (IsIfStart(line))
+ {
+ depth++;
+ continue;
+ }
+
+ if (line == "end_if")
+ {
+ if (depth == 0)
+ {
+ return (i, false);
+ }
+
+ depth--;
+ continue;
+ }
+
+ if (line == "else:" && depth == 0)
+ {
+ return (i, true);
+ }
+ }
+
+ return (-1, false);
+ }
+
+ private int FindEndIf(int currentLine)
+ {
+ int depth = 0;
+
+ for (int i = currentLine + 1; i < RuntimeInfo.Lines.Count; i++)
+ {
+ string line = RuntimeInfo.Lines[i].Content.Trim().Replace("\r", string.Empty);
+
+ if (IsIfStart(line))
+ {
+ depth++;
+ continue;
+ }
+
+ if (line == "end_if")
+ {
+ if (depth == 0)
+ {
+ return i;
+ }
+
+ depth--;
+ }
+ }
+
+ return -1;
+ }
+
+ private static bool IsIfStart(string line)
+ {
+ return line.StartsWith("if ", StringComparison.Ordinal) && line.EndsWith(':');
+ }
+
+ private int FindEndWhile(int currentLine)
+ {
+ int depth = 0;
+
+ for (int i = currentLine + 1; i < RuntimeInfo.Lines.Count; i++)
+ {
+ string line = RuntimeInfo.Lines[i].Content.Trim().Replace("\r", string.Empty);
+
+ if (IsWhileStart(line))
+ {
+ depth++;
+ continue;
+ }
+
+ if (line == "end_while")
+ {
+ if (depth == 0)
+ {
+ return i;
+ }
+
+ depth--;
+ }
+ }
+
+ return -1;
+ }
+
+ private int FindWhile(int currentLine)
+ {
+ int depth = 0;
+
+ for (int i = currentLine - 1; i >= 0; i--)
+ {
+ string line = RuntimeInfo.Lines[i].Content.Trim().Replace("\r", string.Empty);
+
+ if (line == "end_while")
+ {
+ depth++;
+ continue;
+ }
+
+ if (IsWhileStart(line))
+ {
+ if (depth == 0)
+ {
+ return i;
+ }
+
+ depth--;
+ }
+ }
+
+ return -1;
+ }
+
+ private static bool IsWhileStart(string line)
+ {
+ return line.StartsWith("while ", StringComparison.Ordinal) && line.EndsWith(':');
+ }
}
From 317bca84d310770798cadcfc198743015ccb4014 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 14:33:47 +0100
Subject: [PATCH 24/73] Enforce label and function statements to end with ':'
and update syntax checks
---
.../Statements/CodeFlowStatements.cs | 21 +++++++++++++++----
.../Statements/FunctionStatements.cs | 17 +++++++++++++--
2 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/YesNt.Interpreter/Statements/CodeFlowStatements.cs b/YesNt.Interpreter/Statements/CodeFlowStatements.cs
index 38aee20..1000b84 100644
--- a/YesNt.Interpreter/Statements/CodeFlowStatements.cs
+++ b/YesNt.Interpreter/Statements/CodeFlowStatements.cs
@@ -63,10 +63,23 @@ internal class CodeFlowStatements : StatementRuntimeInformation
}
}
- [Statement("label", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, ExecuteInSearchMode = true)]
+ [Statement("label", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, ExecuteInSearchMode = true, Separator = ":")]
public void FindLabel(string args)
{
- string key = NormalizeBlockName(args);
+ string labelDeclaration = args.Trim();
+ if (!labelDeclaration.EndsWith(':'))
+ {
+ RuntimeInfo.Exit("Invalid syntax. Statement must end with ':'", true);
+ return;
+ }
+
+ string key = NormalizeBlockName(labelDeclaration);
+ if (string.IsNullOrWhiteSpace(key))
+ {
+ RuntimeInfo.Exit("Invalid syntax", true);
+ return;
+ }
+
if (RuntimeInfo.Labels.ContainsKey(key))
{
RuntimeInfo.Labels[key] = RuntimeInfo.LineNumber;
@@ -146,7 +159,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
args = args.Trim();
if (!args.EndsWith(':'))
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ RuntimeInfo.Exit("Invalid syntax. Statement must end with ':'", true);
return;
}
@@ -198,7 +211,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
args = args.Trim();
if (!args.EndsWith(':'))
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ RuntimeInfo.Exit("Invalid syntax. Statement must end with ':'", true);
return;
}
diff --git a/YesNt.Interpreter/Statements/FunctionStatements.cs b/YesNt.Interpreter/Statements/FunctionStatements.cs
index 7e50ec4..d975a35 100644
--- a/YesNt.Interpreter/Statements/FunctionStatements.cs
+++ b/YesNt.Interpreter/Statements/FunctionStatements.cs
@@ -10,7 +10,7 @@ namespace YesNt.Interpreter.Statements;
internal class FunctionStatements : StatementRuntimeInformation
{
- [Statement("func", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
+ [Statement("func", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, ExecuteInSearchMode = true, Separator = ":")]
public void FindFunction(string args)
{
if (RuntimeInfo.InternalIsInFunction)
@@ -19,7 +19,20 @@ internal class FunctionStatements : StatementRuntimeInformation
return;
}
- string key = NormalizeBlockName(args);
+ string functionDeclaration = args.Trim();
+ if (!functionDeclaration.EndsWith(':'))
+ {
+ RuntimeInfo.Exit("Invalid syntax. Statement must end with ':'", true);
+ return;
+ }
+
+ string key = NormalizeBlockName(functionDeclaration);
+ if (string.IsNullOrWhiteSpace(key))
+ {
+ RuntimeInfo.Exit("Invalid syntax", true);
+ return;
+ }
+
if (RuntimeInfo.Functions.ContainsKey(key))
{
RuntimeInfo.Functions[key] = RuntimeInfo.LineNumber;
From 36d8735fbbd25cd70c3bf6a3d97cc2e1ab33ad14 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 14:48:04 +0100
Subject: [PATCH 25/73] Remove manual variable declaration highlighting from
SyntaxHighlighter and add color to VariableStatements
---
YesNt.CodeEditor/SyntaxHighlighter.cs | 18 ------------------
.../Statements/VariableStatements.cs | 4 ++--
2 files changed, 2 insertions(+), 20 deletions(-)
diff --git a/YesNt.CodeEditor/SyntaxHighlighter.cs b/YesNt.CodeEditor/SyntaxHighlighter.cs
index a368796..57b9bd2 100644
--- a/YesNt.CodeEditor/SyntaxHighlighter.cs
+++ b/YesNt.CodeEditor/SyntaxHighlighter.cs
@@ -111,18 +111,6 @@ internal partial class SyntaxHighlighter(ReadOnlyCollection
Date: Wed, 4 Mar 2026 14:49:54 +0100
Subject: [PATCH 26/73] Add new tests for console, function, system, variable,
and code flow statements
---
.../CodeFlowStatementsTests.cs | 80 ++++++++++
.../CodeFowStatementsTests.cs | 132 ++++++++++++++++
.../ConsoleStatementsTests.cs | 110 +++++++++++++
.../FunctionStatementsTests.cs | 147 ++++++++++++++++++
.../PredefinedVariableStatementsTests.cs | 107 +++++++++++++
.../ProcessingStatementsTests.cs | 100 +++++++++++-
.../SystemStatementsTests.cs | 48 ++++++
.../VariableStatementsTests.cs | 104 +++++++++++++
YesNt.Interpreter.Tests/YesNtAssert.cs | 127 ++++++++-------
9 files changed, 899 insertions(+), 56 deletions(-)
create mode 100644 YesNt.Interpreter.Tests/CodeFlowStatementsTests.cs
create mode 100644 YesNt.Interpreter.Tests/ConsoleStatementsTests.cs
create mode 100644 YesNt.Interpreter.Tests/FunctionStatementsTests.cs
create mode 100644 YesNt.Interpreter.Tests/PredefinedVariableStatementsTests.cs
create mode 100644 YesNt.Interpreter.Tests/SystemStatementsTests.cs
create mode 100644 YesNt.Interpreter.Tests/VariableStatementsTests.cs
diff --git a/YesNt.Interpreter.Tests/CodeFlowStatementsTests.cs b/YesNt.Interpreter.Tests/CodeFlowStatementsTests.cs
new file mode 100644
index 0000000..6674ac3
--- /dev/null
+++ b/YesNt.Interpreter.Tests/CodeFlowStatementsTests.cs
@@ -0,0 +1,80 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System.Collections.Generic;
+
+namespace YesNt.Interpreter.Tests;
+
+[TestClass]
+public class CodeFlowStatementsTests
+{
+ [TestMethod]
+ public void ExitStopsExecutionTest()
+ {
+ List lines =
+ [
+ "let result = before",
+ "exit",
+ "let result = after",
+ "${result}"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Planned termination by code");
+ }
+
+ [TestMethod]
+ public void AbortAllStopsExecutionTest()
+ {
+ List lines =
+ [
+ "abort_all",
+ "let result = after",
+ "${result}"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Canceling all tasks");
+ }
+
+ [TestMethod]
+ public void ThrowTerminatesWithErrorFlagTest()
+ {
+ List lines =
+ [
+ "throw bad"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "with the message: bad");
+ }
+
+ [TestMethod]
+ public void ErrorTerminatesWithMessageTest()
+ {
+ List lines =
+ [
+ "error soft"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "with the message: soft");
+ }
+
+ [TestMethod]
+ public void MissingLabelFailsTest()
+ {
+ List lines =
+ [
+ "goto nowhere"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Label \"nowhere\" not found");
+ }
+
+ [TestMethod]
+ public void MissingFunctionFailsTest()
+ {
+ List lines =
+ [
+ "call nowhere"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Function \"nowhere\" not found");
+ }
+}
diff --git a/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs b/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
index 6bd75b9..c21063b 100644
--- a/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
@@ -136,4 +136,136 @@ public class CodeFlowTests
YesNtAssert.IsLastLineEqual(lines, "4");
}
+
+ [TestMethod]
+ public void IfElseTrueSkipsElseBranchTest()
+ {
+ List lines =
+ [
+ "let result = 0",
+ "if 2 > 1:",
+ "let result = 1",
+ "else:",
+ "let result = 2",
+ "end_if",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "1");
+ }
+
+ [TestMethod]
+ public void IfWithoutElseFalseSkipsBodyTest()
+ {
+ List lines =
+ [
+ "let result = 5",
+ "if 1 == 2:",
+ "let result = 1",
+ "end_if",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "5");
+ }
+
+ [TestMethod]
+ public void IfGotoTrueTest()
+ {
+ List lines =
+ [
+ "let result = 0",
+ "if 1 == 1 goto done",
+ "let result = 2",
+ "label done:",
+ "let result = ${result} + 1 calc",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "1");
+ }
+
+ [TestMethod]
+ public void IfCallTrueTest()
+ {
+ List lines =
+ [
+ "func set_result:",
+ "global result = ok",
+ "return",
+ "if 1 == 1 call set_result",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "ok");
+ }
+
+ [TestMethod]
+ public void LabelWithoutColonFailsTest()
+ {
+ List lines =
+ [
+ "label loop"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement");
+ }
+
+ [TestMethod]
+ public void FunctionWithoutColonFailsTest()
+ {
+ List lines =
+ [
+ "func missing"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement");
+ }
+
+ [TestMethod]
+ public void MissingEndIfFailsTest()
+ {
+ List lines =
+ [
+ "if 1 == 2:",
+ "let result = 1"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "No matching end_if found");
+ }
+
+ [TestMethod]
+ public void ElseWithoutIfFailsTest()
+ {
+ List lines =
+ [
+ "else:"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "No matching end_if found");
+ }
+
+ [TestMethod]
+ public void MissingEndWhileFailsTest()
+ {
+ List lines =
+ [
+ "let i = 0",
+ "while ${i} > 1:",
+ "let i = ${i} + 1 calc"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "No matching end_while found");
+ }
+
+ [TestMethod]
+ public void EndWhileWithoutWhileFailsTest()
+ {
+ List lines =
+ [
+ "end_while"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "No matching while found");
+ }
}
diff --git a/YesNt.Interpreter.Tests/ConsoleStatementsTests.cs b/YesNt.Interpreter.Tests/ConsoleStatementsTests.cs
new file mode 100644
index 0000000..2e789ba
--- /dev/null
+++ b/YesNt.Interpreter.Tests/ConsoleStatementsTests.cs
@@ -0,0 +1,110 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+using YesNt.Interpreter.Runtime;
+
+namespace YesNt.Interpreter.Tests;
+
+[TestClass]
+public class ConsoleStatementsTests
+{
+ private static readonly object ConsoleLock = new object();
+
+ [TestMethod]
+ public void PrintLineWritesOutputTest()
+ {
+ List lines =
+ [
+ "print_line hello"
+ ];
+
+ YesNtAssert.ContainsDebugOutput(lines, "hello");
+ }
+
+ [TestMethod]
+ public void PrintWritesOutputTest()
+ {
+ List lines =
+ [
+ "print hello"
+ ];
+
+ YesNtAssert.ContainsDebugOutput(lines, "hello");
+ }
+
+ [TestMethod]
+ public void ClearThrowsInNonInteractiveConsoleTest()
+ {
+ List lines =
+ [
+ "clear"
+ ];
+
+ _ = Assert.ThrowsException(() => YesNtAssert.GetLastLine(lines));
+ }
+
+ [TestMethod]
+ public void ReadLineReplacesTokenTest()
+ {
+ lock (ConsoleLock)
+ {
+ TextReader originalIn = Console.In;
+
+ try
+ {
+ Console.SetIn(new StringReader("typed value" + Environment.NewLine));
+
+ List lines =
+ [
+ "let value = %read_line",
+ "${value}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "typed value");
+ }
+ finally
+ {
+ Console.SetIn(originalIn);
+ }
+ }
+ }
+
+ [TestMethod]
+ public void ReadKeyCanBeInterruptedByStopTest()
+ {
+ YesNtInterpreter interpreter = new YesNtInterpreter();
+ interpreter.Initialize();
+
+ AutoResetEvent onDone = new AutoResetEvent(false);
+ StringBuilder output = new StringBuilder();
+
+ interpreter.OnDebugOutput += (s) => _ = output.Append(s);
+ interpreter.OnLineExecuted += (e) =>
+ {
+ if (e is null)
+ {
+ _ = onDone.Set();
+ }
+ };
+
+ List lines =
+ [
+ "let value = %read_key"
+ ];
+
+ _ = Task.Run(() => interpreter.Execute(lines, true));
+
+ Thread.Sleep(100);
+ interpreter.Stop();
+
+ _ = onDone.WaitOne(TimeSpan.FromSeconds(3));
+
+ StringAssert.Contains(output.ToString(), "Terminated by external process");
+ }
+}
diff --git a/YesNt.Interpreter.Tests/FunctionStatementsTests.cs b/YesNt.Interpreter.Tests/FunctionStatementsTests.cs
new file mode 100644
index 0000000..7203cf6
--- /dev/null
+++ b/YesNt.Interpreter.Tests/FunctionStatementsTests.cs
@@ -0,0 +1,147 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System.Collections.Generic;
+
+namespace YesNt.Interpreter.Tests;
+
+[TestClass]
+public class FunctionStatementsTests
+{
+ [TestMethod]
+ public void FunctionCallWithInParameterTest()
+ {
+ List lines =
+ [
+ "goto main",
+ "func echo:",
+ "global result = %in",
+ "return",
+ "label main:",
+ "call echo with hello",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "hello");
+ }
+
+ [TestMethod]
+ public void HasInAndHasOutTokensTest()
+ {
+ List lines =
+ [
+ "goto main",
+ "func probe:",
+ "global hasInBefore = %has_in",
+ "let consume = %in",
+ "global hasInAfter = %has_in",
+ "push_out ${hasInBefore}",
+ "push_out ${hasInAfter}",
+ "return",
+ "label main:",
+ "call probe with x",
+ "let hasOut = %has_out",
+ "${hasOut}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "True");
+ }
+
+ [TestMethod]
+ public void OutParameterReadTest()
+ {
+ List lines =
+ [
+ "goto main",
+ "func make:",
+ "push_out out_value",
+ "return",
+ "label main:",
+ "call make with anything",
+ "let value = %out",
+ "${value}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "out_value");
+ }
+
+ [TestMethod]
+ public void OutParameterWithoutValueFailsTest()
+ {
+ List lines =
+ [
+ "let x = %out"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "No out argument in stack");
+ }
+
+ [TestMethod]
+ public void InParameterOutsideFunctionFailsTest()
+ {
+ List lines =
+ [
+ "let x = %in"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Statement not allowed outside of function");
+ }
+
+ [TestMethod]
+ public void ReturnOutsideFunctionFailsTest()
+ {
+ List lines =
+ [
+ "return"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Statement not allowed outside of function");
+ }
+
+ [TestMethod]
+ public void PushOutOutsideFunctionFailsTest()
+ {
+ List lines =
+ [
+ "push_out value"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Statement not allowed outside of function");
+ }
+
+ [TestMethod]
+ public void FunctionWithoutColonFailsTest()
+ {
+ List lines =
+ [
+ "func missing"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement");
+ }
+
+ [TestMethod]
+ public void NestedFunctionDefinitionFailsTest()
+ {
+ List lines =
+ [
+ "func outer:",
+ "func inner:",
+ "return"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Nested functions are not allowed");
+ }
+
+ [TestMethod]
+ public void ClearCallStackRunsTest()
+ {
+ List lines =
+ [
+ "clear_call_stack",
+ "let result = ok",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "ok");
+ }
+}
diff --git a/YesNt.Interpreter.Tests/PredefinedVariableStatementsTests.cs b/YesNt.Interpreter.Tests/PredefinedVariableStatementsTests.cs
new file mode 100644
index 0000000..cf4b6c9
--- /dev/null
+++ b/YesNt.Interpreter.Tests/PredefinedVariableStatementsTests.cs
@@ -0,0 +1,107 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System;
+using System.Collections.Generic;
+
+namespace YesNt.Interpreter.Tests;
+
+[TestClass]
+public class PredefinedVariableStatementsTests
+{
+ [TestMethod]
+ public void TimeTokenProducesUnixTimestampTest()
+ {
+ List lines =
+ [
+ "%time"
+ ];
+
+ string? value = YesNtAssert.GetLastLine(lines);
+ Assert.IsNotNull(value);
+ Assert.IsTrue(long.TryParse(value, out long parsed));
+
+ long now = DateTimeOffset.Now.ToUnixTimeSeconds();
+ Assert.IsTrue(Math.Abs(now - parsed) < 10);
+ }
+
+ [TestMethod]
+ public void OsTokenProducesValueTest()
+ {
+ List lines =
+ [
+ "%os"
+ ];
+
+ string? value = YesNtAssert.GetLastLine(lines);
+ Assert.IsFalse(string.IsNullOrWhiteSpace(value));
+ }
+
+ [TestMethod]
+ public void CpuTokenProducesValueTest()
+ {
+ List lines =
+ [
+ "%cpu"
+ ];
+
+ string? value = YesNtAssert.GetLastLine(lines);
+ Assert.IsFalse(string.IsNullOrWhiteSpace(value));
+ }
+
+ [TestMethod]
+ public void Is64TokenProducesBooleanTest()
+ {
+ List lines =
+ [
+ "%is64"
+ ];
+
+ string? value = YesNtAssert.GetLastLine(lines);
+ Assert.AreEqual(Environment.Is64BitOperatingSystem.ToString(), value);
+ }
+
+ [TestMethod]
+ public void PiTokenProducesPiTest()
+ {
+ List lines =
+ [
+ "%pi"
+ ];
+
+ string? value = YesNtAssert.GetLastLine(lines);
+ Assert.IsNotNull(value);
+ Assert.IsTrue(double.TryParse(value, out double parsed));
+ Assert.IsTrue(Math.Abs(parsed - Math.PI) < 0.001d);
+ }
+
+ [TestMethod]
+ public void RandTokenProducesIntegerTest()
+ {
+ List lines =
+ [
+ "%rand"
+ ];
+
+ string? value = YesNtAssert.GetLastLine(lines);
+ Assert.IsNotNull(value);
+ Assert.IsTrue(int.TryParse(value, out int parsed));
+ Assert.IsTrue(parsed >= 32767);
+ }
+
+ [TestMethod]
+ public void MultipleRandTokensAreReplacedTest()
+ {
+ List lines =
+ [
+ "%rand %rand"
+ ];
+
+ string? value = YesNtAssert.GetLastLine(lines);
+ Assert.IsNotNull(value);
+
+ string[] parts = value.Split(' ', StringSplitOptions.RemoveEmptyEntries);
+ Assert.AreEqual(2, parts.Length);
+ Assert.IsTrue(int.TryParse(parts[0], out _));
+ Assert.IsTrue(int.TryParse(parts[1], out _));
+ }
+}
diff --git a/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs b/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
index fd68646..bbfd2ef 100644
--- a/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
@@ -1,4 +1,8 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System;
+using System.Collections.Generic;
+using System.IO;
namespace YesNt.Interpreter.Tests;
@@ -40,4 +44,98 @@ public class ProcessingStatementsTests
{
YesNtAssert.IsLineEqual("2 ^ 3 calc", "8");
}
+
+ [TestMethod]
+ public void EvalDecodesSafeStringTest()
+ {
+ YesNtAssert.IsLineEqual("hello~nliworld eval", "hello\nworld");
+ }
+
+ [TestMethod]
+ public void SleepInvalidValueFailsTest()
+ {
+ List lines =
+ [
+ "sleep nope"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "\"nope\" is not a valid time-out value");
+ }
+
+ [TestMethod]
+ public void SleepRunsAndContinuesTest()
+ {
+ List lines =
+ [
+ "sleep 5",
+ "let result = ok",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "ok");
+ }
+
+ [TestMethod]
+ public void LengthPushesOutParameterTest()
+ {
+ List lines =
+ [
+ "length hello",
+ "let value = %out",
+ "${value}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "5");
+ }
+
+ [TestMethod]
+ public void ImportLoadsScriptTest()
+ {
+ string tempFile = Path.Combine(Path.GetTempPath(), $"yesnt-import-{Guid.NewGuid():N}.ynt");
+
+ try
+ {
+ File.WriteAllText(tempFile, "let imported = yes");
+
+ List lines =
+ [
+ $"import {tempFile}",
+ "${imported}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "yes");
+ }
+ finally
+ {
+ if (File.Exists(tempFile))
+ {
+ File.Delete(tempFile);
+ }
+ }
+ }
+
+ [TestMethod]
+ public void ImportMissingFileFailsTest()
+ {
+ List lines =
+ [
+ $"import {Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"))}.ynt"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Could not find file");
+ }
+
+ [TestMethod]
+ public void TaskCanUpdateGlobalVariableTest()
+ {
+ List lines =
+ [
+ "global result = 0",
+ "global result = 1 task",
+ "sleep 50",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "1", timeout: 3000);
+ }
}
diff --git a/YesNt.Interpreter.Tests/SystemStatementsTests.cs b/YesNt.Interpreter.Tests/SystemStatementsTests.cs
new file mode 100644
index 0000000..441eefc
--- /dev/null
+++ b/YesNt.Interpreter.Tests/SystemStatementsTests.cs
@@ -0,0 +1,48 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System.Collections.Generic;
+
+namespace YesNt.Interpreter.Tests;
+
+[TestClass]
+public class SystemStatementsTests
+{
+ [TestMethod]
+ public void ExecWithArgsRunsProcessTest()
+ {
+ List lines =
+ [
+ "exec cmd with /c,echo yesnt",
+ "let exitCode = %out",
+ "${exitCode}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "0");
+ }
+
+ [TestMethod]
+ public void ExecWithInStackArgsRunsProcessTest()
+ {
+ List lines =
+ [
+ "push_in /c",
+ "push_in echo yesnt",
+ "exec cmd",
+ "let exitCode = %out",
+ "${exitCode}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "0");
+ }
+
+ [TestMethod]
+ public void ExecInvalidProgramFailsTest()
+ {
+ List lines =
+ [
+ "exec does_not_exist_abc_xyz"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Failed to start \"does_not_exist_abc_xyz\"");
+ }
+}
diff --git a/YesNt.Interpreter.Tests/VariableStatementsTests.cs b/YesNt.Interpreter.Tests/VariableStatementsTests.cs
new file mode 100644
index 0000000..260e796
--- /dev/null
+++ b/YesNt.Interpreter.Tests/VariableStatementsTests.cs
@@ -0,0 +1,104 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System.Collections.Generic;
+
+namespace YesNt.Interpreter.Tests;
+
+[TestClass]
+public class VariableStatementsTests
+{
+ [TestMethod]
+ public void LetAndReadVariableTest()
+ {
+ List lines =
+ [
+ "let value = hi",
+ "${value}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "hi");
+ }
+
+ [TestMethod]
+ public void GlobalVariableReadTest()
+ {
+ List lines =
+ [
+ "global value = hi",
+ "${value}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "hi");
+ }
+
+ [TestMethod]
+ public void LocalVariableOverridesGlobalTest()
+ {
+ List lines =
+ [
+ "global value = global",
+ "let value = local",
+ "${value}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "local");
+ }
+
+ [TestMethod]
+ public void DeleteLocalVariableTest()
+ {
+ List lines =
+ [
+ "let value = a",
+ "delete value",
+ "global value = b",
+ "${value}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "b");
+ }
+
+ [TestMethod]
+ public void DeleteMissingVariableFailsTest()
+ {
+ List lines =
+ [
+ "delete missing"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Variable \"missing\" not found");
+ }
+
+ [TestMethod]
+ public void LetInvalidSyntaxFailsTest()
+ {
+ List lines =
+ [
+ "let a"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement");
+ }
+
+ [TestMethod]
+ public void LetInvalidNameFailsTest()
+ {
+ List lines =
+ [
+ "let a b = 1"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Invalid Syntax");
+ }
+
+ [TestMethod]
+ public void MissingVariableReferenceFailsTest()
+ {
+ List lines =
+ [
+ "${missing}"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Variable \"missing\" not found");
+ }
+}
diff --git a/YesNt.Interpreter.Tests/YesNtAssert.cs b/YesNt.Interpreter.Tests/YesNtAssert.cs
index 66638d9..25c86f3 100644
--- a/YesNt.Interpreter.Tests/YesNtAssert.cs
+++ b/YesNt.Interpreter.Tests/YesNtAssert.cs
@@ -1,7 +1,9 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Text;
using System.Threading;
using YesNt.Interpreter.Runtime;
@@ -10,76 +12,91 @@ namespace YesNt.Interpreter.Tests;
internal static class YesNtAssert
{
- private static readonly YesNtInterpreter yesNtInterpreter = new YesNtInterpreter();
-
- static YesNtAssert()
- {
- yesNtInterpreter.Initialize();
- }
-
public static void IsLastLineEqual(List lines, string expected, int timeout = 1000)
{
+ (DebugEventArgs? debugEventArgs, _) = ExecuteAndCapture(lines, timeout);
+ Assert.AreEqual(expected, debugEventArgs?.CurrentLine);
+ }
+
+ public static void IsLineEqual(string line, string expected, int timeout = 1000)
+ {
+ List lines =
+ [
+ line
+ ];
+
+ (DebugEventArgs? debugEventArgs, _) = ExecuteAndCapture(lines, timeout);
+ Assert.AreEqual(expected, debugEventArgs?.CurrentLine);
+ }
+
+ public static void IsLineNotEqual(string line, string expected, int timeout = 1000)
+ {
+ List lines =
+ [
+ line
+ ];
+
+ (DebugEventArgs? debugEventArgs, _) = ExecuteAndCapture(lines, timeout);
+ Assert.AreNotEqual(expected, debugEventArgs?.CurrentLine);
+ }
+
+ public static void ContainsTerminationMessage(List lines, string expectedMessageFragment, int timeout = 1000)
+ {
+ (_, string debugOutput) = ExecuteAndCapture(lines, timeout);
+
+ StringAssert.Contains(debugOutput, expectedMessageFragment);
+ }
+
+ public static void ContainsDebugOutput(List lines, string expectedFragment, int timeout = 1000)
+ {
+ (_, string debugOutput) = ExecuteAndCapture(lines, timeout);
+
+ StringAssert.Contains(debugOutput, expectedFragment);
+ }
+
+ public static string? GetLastLine(List lines, int timeout = 1000)
+ {
+ (DebugEventArgs? debugEventArgs, _) = ExecuteAndCapture(lines, timeout);
+ return debugEventArgs?.CurrentLine;
+ }
+
+ public static void LastLineMatches(List lines, string pattern, int timeout = 1000)
+ {
+ string? value = GetLastLine(lines, timeout);
+ Assert.IsNotNull(value);
+ StringAssert.Matches(value, new Regex(pattern));
+ }
+
+ private static (DebugEventArgs? LastDebugEvent, string DebugOutput) ExecuteAndCapture(List lines, int timeout)
+ {
+ YesNtInterpreter yesNtInterpreter = new YesNtInterpreter();
+ yesNtInterpreter.Initialize();
+
AutoResetEvent onDone = new AutoResetEvent(false);
+ DebugEventArgs? debugEventArgs = null;
+ StringBuilder outputBuilder = new StringBuilder();
- DebugEventArgs debugEventArgs = new DebugEventArgs();
yesNtInterpreter.OnLineExecuted += (er) =>
{
- debugEventArgs = er ?? debugEventArgs;
-
- if (er is null)
+ if (er is not null)
+ {
+ debugEventArgs = er;
+ }
+ else
{
_ = onDone.Set();
}
};
- yesNtInterpreter.Execute(lines, true);
-
- _ = onDone.WaitOne(TimeSpan.FromSeconds(timeout));
-
- Assert.AreEqual(expected, debugEventArgs.CurrentLine);
- }
-
- public static void IsLineEqual(string line, string expected, int timeout = 1000)
- {
- AutoResetEvent onDone = new AutoResetEvent(false);
- List lines =
- [
- line
- ];
-
- DebugEventArgs debugEventArgs = new DebugEventArgs();
- yesNtInterpreter.OnLineExecuted += (er) =>
+ yesNtInterpreter.OnDebugOutput += (s) =>
{
- debugEventArgs = er ?? debugEventArgs;
- _ = onDone.Set();
+ _ = outputBuilder.Append(s);
};
yesNtInterpreter.Execute(lines, true);
_ = onDone.WaitOne(TimeSpan.FromMilliseconds(timeout));
- Assert.AreEqual(expected, debugEventArgs.CurrentLine);
+ return (debugEventArgs, outputBuilder.ToString());
}
-
- public static void IsLineNotEqual(string line, string expected, int timeout = 1000)
- {
- AutoResetEvent onDone = new AutoResetEvent(false);
- List lines =
- [
- line
- ];
-
- DebugEventArgs debugEventArgs = new DebugEventArgs();
- yesNtInterpreter.OnLineExecuted += (er) =>
- {
- debugEventArgs = er ?? debugEventArgs;
- _ = onDone.Set();
- };
-
- yesNtInterpreter.Execute(lines, true);
-
- _ = onDone.WaitOne(TimeSpan.FromMilliseconds(timeout));
-
- Assert.AreNotEqual(expected, debugEventArgs.CurrentLine);
- }
-}
\ No newline at end of file
+}
From d4cc1d1c28aaa0fad76110ec62fb940bbc702e1a Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 14:55:09 +0100
Subject: [PATCH 27/73] Use var instead of let for variables
---
README.md | 3 +-
SYNTAX_V2.md | 9 +--
.../CodeFlowStatementsTests.cs | 7 ++-
.../CodeFowStatementsTests.cs | 63 ++++++++++---------
.../ConsoleStatementsTests.cs | 5 +-
.../FunctionStatementsTests.cs | 13 ++--
.../ProcessingStatementsTests.cs | 7 ++-
.../SystemStatementsTests.cs | 5 +-
.../VariableStatementsTests.cs | 11 ++--
.../Statements/VariableStatements.cs | 5 +-
10 files changed, 69 insertions(+), 59 deletions(-)
diff --git a/README.md b/README.md
index 5a83f33..bf67f69 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Current language syntax is documented in [SYNTAX_V2.md](SYNTAX_V2.md).
Example:
```ynt
-let name = world
+var name = world
print_line Hello ${name}
```
@@ -18,3 +18,4 @@ print_line Hello ${name}
```bash
dotnet run --project YesNt.Interpreter -- path/to/script.ynt
```
+
diff --git a/SYNTAX_V2.md b/SYNTAX_V2.md
index ab96d1d..dd62b7a 100644
--- a/SYNTAX_V2.md
+++ b/SYNTAX_V2.md
@@ -20,7 +20,7 @@ This document describes the current, word-based YesNt syntax.
## Quick Example
```ynt
-let name = world
+var name = world
func greet:
print_line Hello ${name}
return
@@ -40,10 +40,10 @@ end_if
## While Loops
```ynt
-let i = 3
+var i = 3
while ${i} > 0:
print_line ${i}
-let i = ${i} - 1 calc
+var i = ${i} - 1 calc
end_while
```
@@ -51,7 +51,7 @@ end_while
| Area | v1 Syntax | v2 Syntax | Notes |
|---|---|---|---|
-| Variables | `x` | `${x}` | Variable read/interpolation token. |
@@ -99,3 +99,4 @@ end_while
- `%out` is intentionally kept as `%out`.
- Postfix operations are `calc`, `eval`, and `task`.
+
diff --git a/YesNt.Interpreter.Tests/CodeFlowStatementsTests.cs b/YesNt.Interpreter.Tests/CodeFlowStatementsTests.cs
index 6674ac3..0c00e1f 100644
--- a/YesNt.Interpreter.Tests/CodeFlowStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/CodeFlowStatementsTests.cs
@@ -12,9 +12,9 @@ public class CodeFlowStatementsTests
{
List lines =
[
- "let result = before",
+ "var result = before",
"exit",
- "let result = after",
+ "var result = after",
"${result}"
];
@@ -27,7 +27,7 @@ public class CodeFlowStatementsTests
List lines =
[
"abort_all",
- "let result = after",
+ "var result = after",
"${result}"
];
@@ -78,3 +78,4 @@ public class CodeFlowStatementsTests
YesNtAssert.ContainsTerminationMessage(lines, "Function \"nowhere\" not found");
}
}
+
diff --git a/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs b/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
index c21063b..a3c0527 100644
--- a/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/CodeFowStatementsTests.cs
@@ -26,9 +26,9 @@ public class CodeFlowTests
{
List lines =
[
- "let result = 1",
+ "var result = 1",
"goto yes",
- "let result = 0",
+ "var result = 0",
"label yes:",
"${result}"
];
@@ -40,9 +40,9 @@ public class CodeFlowTests
{
List lines =
[
- "let result = low",
+ "var result = low",
"if 6 > 5:",
- "let result = high",
+ "var result = high",
"end_if",
"${result}"
];
@@ -55,11 +55,11 @@ public class CodeFlowTests
{
List lines =
[
- "let result = low",
+ "var result = low",
"if 6 < 5:",
- "let result = high",
+ "var result = high",
"else:",
- "let result = medium",
+ "var result = medium",
"end_if",
"${result}"
];
@@ -72,12 +72,12 @@ public class CodeFlowTests
{
List lines =
[
- "let result = 0",
+ "var result = 0",
"if 1 == 1:",
"if 2 == 3:",
- "let result = 1",
+ "var result = 1",
"else:",
- "let result = 2",
+ "var result = 2",
"end_if",
"end_if",
"${result}"
@@ -91,9 +91,9 @@ public class CodeFlowTests
{
List lines =
[
- "let i = 3",
+ "var i = 3",
"while ${i} > 0:",
- "let i = ${i} - 1 calc",
+ "var i = ${i} - 1 calc",
"end_while",
"${i}"
];
@@ -106,9 +106,9 @@ public class CodeFlowTests
{
List lines =
[
- "let i = 0",
+ "var i = 0",
"while ${i} > 0:",
- "let i = 99",
+ "var i = 99",
"end_while",
"${i}"
];
@@ -121,15 +121,15 @@ public class CodeFlowTests
{
List lines =
[
- "let outer = 2",
- "let count = 0",
+ "var outer = 2",
+ "var count = 0",
"while ${outer} > 0:",
- "let inner = 2",
+ "var inner = 2",
"while ${inner} > 0:",
- "let count = ${count} + 1 calc",
- "let inner = ${inner} - 1 calc",
+ "var count = ${count} + 1 calc",
+ "var inner = ${inner} - 1 calc",
"end_while",
- "let outer = ${outer} - 1 calc",
+ "var outer = ${outer} - 1 calc",
"end_while",
"${count}"
];
@@ -142,11 +142,11 @@ public class CodeFlowTests
{
List lines =
[
- "let result = 0",
+ "var result = 0",
"if 2 > 1:",
- "let result = 1",
+ "var result = 1",
"else:",
- "let result = 2",
+ "var result = 2",
"end_if",
"${result}"
];
@@ -159,9 +159,9 @@ public class CodeFlowTests
{
List lines =
[
- "let result = 5",
+ "var result = 5",
"if 1 == 2:",
- "let result = 1",
+ "var result = 1",
"end_if",
"${result}"
];
@@ -174,11 +174,11 @@ public class CodeFlowTests
{
List lines =
[
- "let result = 0",
+ "var result = 0",
"if 1 == 1 goto done",
- "let result = 2",
+ "var result = 2",
"label done:",
- "let result = ${result} + 1 calc",
+ "var result = ${result} + 1 calc",
"${result}"
];
@@ -228,7 +228,7 @@ public class CodeFlowTests
List lines =
[
"if 1 == 2:",
- "let result = 1"
+ "var result = 1"
];
YesNtAssert.ContainsTerminationMessage(lines, "No matching end_if found");
@@ -250,9 +250,9 @@ public class CodeFlowTests
{
List lines =
[
- "let i = 0",
+ "var i = 0",
"while ${i} > 1:",
- "let i = ${i} + 1 calc"
+ "var i = ${i} + 1 calc"
];
YesNtAssert.ContainsTerminationMessage(lines, "No matching end_while found");
@@ -269,3 +269,4 @@ public class CodeFlowTests
YesNtAssert.ContainsTerminationMessage(lines, "No matching while found");
}
}
+
diff --git a/YesNt.Interpreter.Tests/ConsoleStatementsTests.cs b/YesNt.Interpreter.Tests/ConsoleStatementsTests.cs
index 2e789ba..fc076b7 100644
--- a/YesNt.Interpreter.Tests/ConsoleStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/ConsoleStatementsTests.cs
@@ -62,7 +62,7 @@ public class ConsoleStatementsTests
List lines =
[
- "let value = %read_line",
+ "var value = %read_line",
"${value}"
];
@@ -95,7 +95,7 @@ public class ConsoleStatementsTests
List lines =
[
- "let value = %read_key"
+ "var value = %read_key"
];
_ = Task.Run(() => interpreter.Execute(lines, true));
@@ -108,3 +108,4 @@ public class ConsoleStatementsTests
StringAssert.Contains(output.ToString(), "Terminated by external process");
}
}
+
diff --git a/YesNt.Interpreter.Tests/FunctionStatementsTests.cs b/YesNt.Interpreter.Tests/FunctionStatementsTests.cs
index 7203cf6..aa148b9 100644
--- a/YesNt.Interpreter.Tests/FunctionStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/FunctionStatementsTests.cs
@@ -32,14 +32,14 @@ public class FunctionStatementsTests
"goto main",
"func probe:",
"global hasInBefore = %has_in",
- "let consume = %in",
+ "var consume = %in",
"global hasInAfter = %has_in",
"push_out ${hasInBefore}",
"push_out ${hasInAfter}",
"return",
"label main:",
"call probe with x",
- "let hasOut = %has_out",
+ "var hasOut = %has_out",
"${hasOut}"
];
@@ -57,7 +57,7 @@ public class FunctionStatementsTests
"return",
"label main:",
"call make with anything",
- "let value = %out",
+ "var value = %out",
"${value}"
];
@@ -69,7 +69,7 @@ public class FunctionStatementsTests
{
List lines =
[
- "let x = %out"
+ "var x = %out"
];
YesNtAssert.ContainsTerminationMessage(lines, "No out argument in stack");
@@ -80,7 +80,7 @@ public class FunctionStatementsTests
{
List lines =
[
- "let x = %in"
+ "var x = %in"
];
YesNtAssert.ContainsTerminationMessage(lines, "Statement not allowed outside of function");
@@ -138,10 +138,11 @@ public class FunctionStatementsTests
List lines =
[
"clear_call_stack",
- "let result = ok",
+ "var result = ok",
"${result}"
];
YesNtAssert.IsLastLineEqual(lines, "ok");
}
}
+
diff --git a/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs b/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
index bbfd2ef..98a093e 100644
--- a/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
@@ -68,7 +68,7 @@ public class ProcessingStatementsTests
List lines =
[
"sleep 5",
- "let result = ok",
+ "var result = ok",
"${result}"
];
@@ -81,7 +81,7 @@ public class ProcessingStatementsTests
List lines =
[
"length hello",
- "let value = %out",
+ "var value = %out",
"${value}"
];
@@ -95,7 +95,7 @@ public class ProcessingStatementsTests
try
{
- File.WriteAllText(tempFile, "let imported = yes");
+ File.WriteAllText(tempFile, "var imported = yes");
List lines =
[
@@ -139,3 +139,4 @@ public class ProcessingStatementsTests
YesNtAssert.IsLastLineEqual(lines, "1", timeout: 3000);
}
}
+
diff --git a/YesNt.Interpreter.Tests/SystemStatementsTests.cs b/YesNt.Interpreter.Tests/SystemStatementsTests.cs
index 441eefc..fa7ec65 100644
--- a/YesNt.Interpreter.Tests/SystemStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/SystemStatementsTests.cs
@@ -13,7 +13,7 @@ public class SystemStatementsTests
List lines =
[
"exec cmd with /c,echo yesnt",
- "let exitCode = %out",
+ "var exitCode = %out",
"${exitCode}"
];
@@ -28,7 +28,7 @@ public class SystemStatementsTests
"push_in /c",
"push_in echo yesnt",
"exec cmd",
- "let exitCode = %out",
+ "var exitCode = %out",
"${exitCode}"
];
@@ -46,3 +46,4 @@ public class SystemStatementsTests
YesNtAssert.ContainsTerminationMessage(lines, "Failed to start \"does_not_exist_abc_xyz\"");
}
}
+
diff --git a/YesNt.Interpreter.Tests/VariableStatementsTests.cs b/YesNt.Interpreter.Tests/VariableStatementsTests.cs
index 260e796..ed1f3ec 100644
--- a/YesNt.Interpreter.Tests/VariableStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/VariableStatementsTests.cs
@@ -12,7 +12,7 @@ public class VariableStatementsTests
{
List lines =
[
- "let value = hi",
+ "var value = hi",
"${value}"
];
@@ -37,7 +37,7 @@ public class VariableStatementsTests
List lines =
[
"global value = global",
- "let value = local",
+ "var value = local",
"${value}"
];
@@ -49,7 +49,7 @@ public class VariableStatementsTests
{
List lines =
[
- "let value = a",
+ "var value = a",
"delete value",
"global value = b",
"${value}"
@@ -74,7 +74,7 @@ public class VariableStatementsTests
{
List lines =
[
- "let a"
+ "var a"
];
YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement");
@@ -85,7 +85,7 @@ public class VariableStatementsTests
{
List lines =
[
- "let a b = 1"
+ "var a b = 1"
];
YesNtAssert.ContainsTerminationMessage(lines, "Invalid Syntax");
@@ -102,3 +102,4 @@ public class VariableStatementsTests
YesNtAssert.ContainsTerminationMessage(lines, "Variable \"missing\" not found");
}
}
+
diff --git a/YesNt.Interpreter/Statements/VariableStatements.cs b/YesNt.Interpreter/Statements/VariableStatements.cs
index 3decc2c..b4cf6d8 100644
--- a/YesNt.Interpreter/Statements/VariableStatements.cs
+++ b/YesNt.Interpreter/Statements/VariableStatements.cs
@@ -1,4 +1,4 @@
-using System.Text.RegularExpressions;
+using System.Text.RegularExpressions;
using YesNt.Interpreter.Attributes;
using YesNt.Interpreter.Enums;
@@ -8,7 +8,7 @@ namespace YesNt.Interpreter.Statements;
internal partial class VariableStatements : StatementRuntimeInformation
{
- [Statement("let", SearchMode.StartOfLine, SpaceAround.End, System.ConsoleColor.DarkBlue, Priority = Priority.VeryLow, Separator = "=")]
+ [Statement("var", SearchMode.StartOfLine, SpaceAround.End, System.ConsoleColor.DarkBlue, Priority = Priority.VeryLow, Separator = "=")]
public void DefineVariable(string args)
{
string[] parts = args.Split('=');
@@ -118,3 +118,4 @@ internal partial class VariableStatements : StatementRuntimeInformation
[GeneratedRegex("\\$\\{([a-zA-Z0-9]+)\\}")]
private static partial Regex VariableStatementRegex();
}
+
From 344e9e644e370991463afb142a96ee9ca0a67016 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 15:06:43 +0100
Subject: [PATCH 28/73] Use source generator instead of reflection
---
YesNt-Interpreter.sln | 28 ++
.../StatementRegistryGenerator.cs | 243 ++++++++++++++++++
.../YesNt.Interpreter.Generator.csproj | 13 +
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 45 +---
YesNt.Interpreter/YesNt.Interpreter.csproj | 8 +-
5 files changed, 294 insertions(+), 43 deletions(-)
create mode 100644 YesNt.Interpreter.Generator/StatementRegistryGenerator.cs
create mode 100644 YesNt.Interpreter.Generator/YesNt.Interpreter.Generator.csproj
diff --git a/YesNt-Interpreter.sln b/YesNt-Interpreter.sln
index 0181ad5..b2c2492 100644
--- a/YesNt-Interpreter.sln
+++ b/YesNt-Interpreter.sln
@@ -14,38 +14,66 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YesNt.Interpreter.Tests", "YesNt.Interpreter.Tests\YesNt.Interpreter.Tests.csproj", "{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YesNt.Interpreter.Generator", "YesNt.Interpreter.Generator\YesNt.Interpreter.Generator.csproj", "{85AAB233-9C4D-4B42-8117-00010958DD1D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Debug|x64.ActiveCfg = Debug|x64
{33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Debug|x64.Build.0 = Debug|x64
+ {33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Debug|x86.Build.0 = Debug|Any CPU
{33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Release|Any CPU.Build.0 = Release|Any CPU
{33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Release|x64.ActiveCfg = Release|x64
{33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Release|x64.Build.0 = Release|x64
+ {33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Release|x86.ActiveCfg = Release|Any CPU
+ {33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Release|x86.Build.0 = Release|Any CPU
{E40573DB-912A-4871-BB65-3EE6E7D72E79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E40573DB-912A-4871-BB65-3EE6E7D72E79}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E40573DB-912A-4871-BB65-3EE6E7D72E79}.Debug|x64.ActiveCfg = Debug|x64
{E40573DB-912A-4871-BB65-3EE6E7D72E79}.Debug|x64.Build.0 = Debug|x64
+ {E40573DB-912A-4871-BB65-3EE6E7D72E79}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E40573DB-912A-4871-BB65-3EE6E7D72E79}.Debug|x86.Build.0 = Debug|Any CPU
{E40573DB-912A-4871-BB65-3EE6E7D72E79}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E40573DB-912A-4871-BB65-3EE6E7D72E79}.Release|Any CPU.Build.0 = Release|Any CPU
{E40573DB-912A-4871-BB65-3EE6E7D72E79}.Release|x64.ActiveCfg = Release|x64
{E40573DB-912A-4871-BB65-3EE6E7D72E79}.Release|x64.Build.0 = Release|x64
+ {E40573DB-912A-4871-BB65-3EE6E7D72E79}.Release|x86.ActiveCfg = Release|Any CPU
+ {E40573DB-912A-4871-BB65-3EE6E7D72E79}.Release|x86.Build.0 = Release|Any CPU
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Debug|x64.ActiveCfg = Debug|x64
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Debug|x64.Build.0 = Debug|x64
+ {2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Debug|x86.Build.0 = Debug|Any CPU
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Release|Any CPU.Build.0 = Release|Any CPU
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Release|x64.ActiveCfg = Release|x64
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Release|x64.Build.0 = Release|x64
+ {2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Release|x86.ActiveCfg = Release|Any CPU
+ {2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Release|x86.Build.0 = Release|Any CPU
+ {85AAB233-9C4D-4B42-8117-00010958DD1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {85AAB233-9C4D-4B42-8117-00010958DD1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {85AAB233-9C4D-4B42-8117-00010958DD1D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {85AAB233-9C4D-4B42-8117-00010958DD1D}.Debug|x64.Build.0 = Debug|Any CPU
+ {85AAB233-9C4D-4B42-8117-00010958DD1D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {85AAB233-9C4D-4B42-8117-00010958DD1D}.Debug|x86.Build.0 = Debug|Any CPU
+ {85AAB233-9C4D-4B42-8117-00010958DD1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {85AAB233-9C4D-4B42-8117-00010958DD1D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {85AAB233-9C4D-4B42-8117-00010958DD1D}.Release|x64.ActiveCfg = Release|Any CPU
+ {85AAB233-9C4D-4B42-8117-00010958DD1D}.Release|x64.Build.0 = Release|Any CPU
+ {85AAB233-9C4D-4B42-8117-00010958DD1D}.Release|x86.ActiveCfg = Release|Any CPU
+ {85AAB233-9C4D-4B42-8117-00010958DD1D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs b/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs
new file mode 100644
index 0000000..a228de1
--- /dev/null
+++ b/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs
@@ -0,0 +1,243 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Microsoft.CodeAnalysis;
+
+namespace YesNt.Interpreter.Generator;
+
+[Generator]
+public sealed class StatementRegistryGenerator : ISourceGenerator
+{
+ private const string StatementAttributeName = "YesNt.Interpreter.Attributes.StatementAttribute";
+ private const string StaticStatementAttributeName = "YesNt.Interpreter.Attributes.StaticStatementAttribute";
+
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ }
+
+ public void Execute(GeneratorExecutionContext context)
+ {
+ Compilation compilation = context.Compilation;
+
+ List statementMethods = [];
+ List staticStatementMethods = [];
+
+ CollectMethods(compilation.Assembly.GlobalNamespace, statementMethods, staticStatementMethods);
+
+ string source = GenerateRegistrySource(statementMethods, staticStatementMethods);
+ context.AddSource("GeneratedStatementRegistry.g.cs", source);
+ }
+
+ private static void CollectMethods(
+ INamespaceSymbol namespaceSymbol,
+ List statementMethods,
+ List staticStatementMethods)
+ {
+ foreach (INamespaceSymbol childNamespace in namespaceSymbol.GetNamespaceMembers())
+ {
+ CollectMethods(childNamespace, statementMethods, staticStatementMethods);
+ }
+
+ foreach (INamedTypeSymbol type in namespaceSymbol.GetTypeMembers())
+ {
+ CollectMethods(type, statementMethods, staticStatementMethods);
+ }
+ }
+
+ private static void CollectMethods(
+ INamedTypeSymbol typeSymbol,
+ List statementMethods,
+ List staticStatementMethods)
+ {
+ foreach (ISymbol member in typeSymbol.GetMembers())
+ {
+ if (member is IMethodSymbol method && method.MethodKind == MethodKind.Ordinary)
+ {
+ foreach (AttributeData attribute in method.GetAttributes())
+ {
+ string? attributeName = attribute.AttributeClass?.ToDisplayString();
+ if (attributeName == StatementAttributeName)
+ {
+ statementMethods.Add(new MethodRegistration(typeSymbol, method, attribute));
+ }
+ else if (attributeName == StaticStatementAttributeName)
+ {
+ staticStatementMethods.Add(new MethodRegistration(typeSymbol, method, attribute));
+ }
+ }
+ }
+ }
+
+ foreach (INamedTypeSymbol nestedType in typeSymbol.GetTypeMembers())
+ {
+ CollectMethods(nestedType, statementMethods, staticStatementMethods);
+ }
+ }
+
+ private static string GenerateRegistrySource(
+ List statementMethods,
+ List staticStatementMethods)
+ {
+ StringBuilder sb = new StringBuilder();
+
+ _ = sb.AppendLine("// ");
+ _ = sb.AppendLine("#nullable enable");
+ _ = sb.AppendLine("using System;");
+ _ = sb.AppendLine("using System.Collections.Generic;");
+ _ = sb.AppendLine("using System.Linq;");
+ _ = sb.AppendLine();
+ _ = sb.AppendLine("namespace YesNt.Interpreter.Runtime;");
+ _ = sb.AppendLine();
+ _ = sb.AppendLine("internal static class GeneratedStatementRegistry");
+ _ = sb.AppendLine("{");
+ _ = sb.AppendLine(" internal static void Register(");
+ _ = sb.AppendLine(" RuntimeInformation runtimeInfo,");
+ _ = sb.AppendLine(" out Dictionary> statements,");
+ _ = sb.AppendLine(" out List> staticStatements)");
+ _ = sb.AppendLine(" {");
+
+ List allTypes = statementMethods
+ .Concat(staticStatementMethods)
+ .Select(x => x.ContainingType)
+ .GroupBy(x => x, SymbolEqualityComparer.Default)
+ .Select(g => g.First())
+ .OrderBy(x => x.ToDisplayString())
+ .ToList();
+
+ Dictionary instanceNames = new Dictionary(SymbolEqualityComparer.Default);
+ int index = 0;
+ foreach (INamedTypeSymbol type in allTypes)
+ {
+ string instanceName = $"instance{index++}";
+ instanceNames[type] = instanceName;
+ _ = sb.AppendLine($" var {instanceName} = new global::{type.ToDisplayString()}();");
+ _ = sb.AppendLine($" {instanceName}.RuntimeInfo = runtimeInfo;");
+ }
+
+ _ = 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.StatementAttribute", method.Attribute);
+ _ = sb.AppendLine($" statementEntries.Add(new({attributeCreation}, {instanceName}.{method.Method.Name}));");
+ }
+
+ _ = 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.StaticStatementAttribute", method.Attribute);
+ _ = sb.AppendLine($" staticEntries.Add(new({attributeCreation}, {instanceName}.{method.Method.Name}));");
+ }
+
+ _ = sb.AppendLine(" statements = statementEntries");
+ _ = sb.AppendLine(" .OrderBy(s => s.Key.Priority)");
+ _ = sb.AppendLine(" .ThenByDescending(s => s.Key.Name.Length)");
+ _ = sb.AppendLine(" .ToDictionary(x => x.Key, x => x.Value);");
+ _ = sb.AppendLine();
+ _ = sb.AppendLine(" staticStatements = staticEntries");
+ _ = sb.AppendLine(" .OrderBy(s => s.Key.Priority)");
+ _ = sb.AppendLine(" .ToList();");
+ _ = sb.AppendLine(" }");
+ _ = sb.AppendLine("}");
+
+ return sb.ToString();
+ }
+
+ private static string BuildAttributeCreation(string attributeTypeName, AttributeData attribute)
+ {
+ string ctorArgs = string.Join(", ",
+ attribute.ConstructorArguments.Select(ToLiteral));
+
+ string creation = $"new {attributeTypeName}({ctorArgs})";
+
+ if (attribute.NamedArguments.Length == 0)
+ {
+ return creation;
+ }
+
+ string namedArgs = string.Join(", ",
+ attribute.NamedArguments.Select(arg => $"{arg.Key} = {ToLiteral(arg.Value)}"));
+
+ return $"{creation} {{ {namedArgs} }}";
+ }
+
+ private static string ToLiteral(TypedConstant constant)
+ {
+ if (constant.IsNull)
+ {
+ return "null!";
+ }
+
+ if (constant.Type is null)
+ {
+ return "null!";
+ }
+
+ if (constant.Kind == TypedConstantKind.Enum)
+ {
+ string enumType = $"global::{constant.Type.ToDisplayString()}";
+ object value = constant.Value!;
+ return $"({enumType}){Convert.ToInt64(value)}";
+ }
+
+ return constant.Type.SpecialType switch
+ {
+ SpecialType.System_String => "\"" + EscapeString((string)constant.Value!) + "\"",
+ SpecialType.System_Char => "'" + EscapeChar((char)constant.Value!) + "'",
+ SpecialType.System_Boolean => (bool)constant.Value! ? "true" : "false",
+ SpecialType.System_Int32 => ((int)constant.Value!).ToString(System.Globalization.CultureInfo.InvariantCulture),
+ SpecialType.System_Int64 => ((long)constant.Value!).ToString(System.Globalization.CultureInfo.InvariantCulture) + "L",
+ SpecialType.System_Single => ((float)constant.Value!).ToString(System.Globalization.CultureInfo.InvariantCulture) + "f",
+ SpecialType.System_Double => ((double)constant.Value!).ToString(System.Globalization.CultureInfo.InvariantCulture),
+ _ => constant.Value!.ToString() ?? "null!"
+ };
+ }
+
+ private static string EscapeString(string value)
+ {
+ return value
+ .Replace("\\", "\\\\")
+ .Replace("\"", "\\\"")
+ .Replace("\r", "\\r")
+ .Replace("\n", "\\n")
+ .Replace("\t", "\\t");
+ }
+
+ private static string EscapeChar(char value)
+ {
+ return value switch
+ {
+ '\\' => "\\\\",
+ '\'' => "\\'",
+ '\r' => "\\r",
+ '\n' => "\\n",
+ '\t' => "\\t",
+ _ => value.ToString()
+ };
+ }
+
+ private sealed class MethodRegistration
+ {
+ public MethodRegistration(INamedTypeSymbol containingType, IMethodSymbol method, AttributeData attribute)
+ {
+ ContainingType = containingType;
+ Method = method;
+ Attribute = attribute;
+ }
+
+ public INamedTypeSymbol ContainingType { get; }
+
+ public IMethodSymbol Method { get; }
+
+ public AttributeData Attribute { get; }
+ }
+}
diff --git a/YesNt.Interpreter.Generator/YesNt.Interpreter.Generator.csproj b/YesNt.Interpreter.Generator/YesNt.Interpreter.Generator.csproj
new file mode 100644
index 0000000..4be3731
--- /dev/null
+++ b/YesNt.Interpreter.Generator/YesNt.Interpreter.Generator.csproj
@@ -0,0 +1,13 @@
+
+
+ netstandard2.0
+ latest
+ enable
+ true
+ true
+
+
+
+
+
+
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index 0559a7c..da6aa9a 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
-using System.Reflection;
using YesNt.Interpreter.Attributes;
using YesNt.Interpreter.Enums;
@@ -49,47 +48,9 @@ public class YesNtInterpreter
public void Initialize()
{
- Assembly assembly = Assembly.GetExecutingAssembly();
- Type[] types = assembly.GetTypes();
-
- IEnumerable allStatementRuntimeInfo = types.Where(t => t.IsSubclassOf(typeof(StatementRuntimeInformation)));
-
statements.Clear();
-
- foreach (Type type in allStatementRuntimeInfo)
- {
- object statementInfo = Activator.CreateInstance(type);
-
- MethodInfo[] allMethodInfo = statementInfo.GetType().GetMethods();
-
- StatementRuntimeInformation statementRuntimeInfo = statementInfo as StatementRuntimeInformation;
- statementRuntimeInfo.RuntimeInfo = runtimeInfo;
-
- foreach (MethodInfo methodInfo in allMethodInfo)
- {
- StatementAttribute statementAttribute = methodInfo.GetCustomAttribute();
- if (statementAttribute is not null)
- {
- Action method = methodInfo.CreateDelegate(typeof(Action), statementInfo) as Action;
- statements.Add(statementAttribute, method);
- }
-
- StaticStatementAttribute staticStatementAttribute = methodInfo.GetCustomAttribute();
- if (staticStatementAttribute is not null)
- {
- Action method = methodInfo.CreateDelegate(typeof(Action), statementInfo) as Action;
- staticStatements.Add(new(staticStatementAttribute, method));
- }
- }
- }
-
- statements = statements
- .OrderBy(s => s.Key.Priority)
- .ThenByDescending(s => s.Key.Name.Length)
- .ToDictionary(x => x.Key, x => x.Value);
- staticStatements = staticStatements
- .OrderBy(s => s.Key.Priority)
- .ToList();
+ staticStatements.Clear();
+ GeneratedStatementRegistry.Register(runtimeInfo, out statements, out staticStatements);
runtimeInfo.OnDebugOutput += (s) => OnDebugOutput?.Invoke(s);
runtimeInfo.OnLineExecuted += (DebugEventArgs e) => OnLineExecuted?.Invoke(e);
@@ -283,4 +244,4 @@ public class YesNtInterpreter
return true;
}
-}
\ No newline at end of file
+}
diff --git a/YesNt.Interpreter/YesNt.Interpreter.csproj b/YesNt.Interpreter/YesNt.Interpreter.csproj
index 1093ec0..f6e5bb2 100644
--- a/YesNt.Interpreter/YesNt.Interpreter.csproj
+++ b/YesNt.Interpreter/YesNt.Interpreter.csproj
@@ -1,4 +1,4 @@
-
+
net8.0
@@ -9,4 +9,10 @@
AnyCPU;x64
+
+
+
+
From e99df1e3f2e2259e2b26398e0143d1c448a02a10 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 15:47:54 +0100
Subject: [PATCH 29/73] Add list statement support with tests for creation,
access, and errors
---
SYNTAX_V2.md | 11 +
.../ListStatementsTests.cs | 161 ++++++++++
.../ProcessingStatementsTests.cs | 4 +-
YesNt.Interpreter/Runtime/FunctionScope.cs | 3 +-
.../Runtime/RuntimeInformation.cs | 5 +-
.../Statements/ListStatements.cs | 274 ++++++++++++++++++
6 files changed, 455 insertions(+), 3 deletions(-)
create mode 100644 YesNt.Interpreter.Tests/ListStatementsTests.cs
create mode 100644 YesNt.Interpreter/Statements/ListStatements.cs
diff --git a/SYNTAX_V2.md b/SYNTAX_V2.md
index dd62b7a..690e071 100644
--- a/SYNTAX_V2.md
+++ b/SYNTAX_V2.md
@@ -47,6 +47,17 @@ var i = ${i} - 1 calc
end_while
```
+## Lists
+
+```ynt
+list items new
+list items add apple
+list items add banana
+list items get 1
+var value = %out
+print_line ${value}
+```
+
## Full v1 -> v2 Mapping
| Area | v1 Syntax | v2 Syntax | Notes |
diff --git a/YesNt.Interpreter.Tests/ListStatementsTests.cs b/YesNt.Interpreter.Tests/ListStatementsTests.cs
new file mode 100644
index 0000000..b5a447d
--- /dev/null
+++ b/YesNt.Interpreter.Tests/ListStatementsTests.cs
@@ -0,0 +1,161 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System.Collections.Generic;
+
+namespace YesNt.Interpreter.Tests;
+
+[TestClass]
+public class ListStatementsTests
+{
+ [TestMethod]
+ public void ListCreateAddGetTest()
+ {
+ List lines =
+ [
+ "list items new",
+ "list items add a",
+ "list items add b",
+ "list items get 1",
+ "var result = %out",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "b");
+ }
+
+ [TestMethod]
+ public void ListSetAndInsertTest()
+ {
+ List lines =
+ [
+ "list items new",
+ "list items add a",
+ "list items add c",
+ "list items insert 1 b",
+ "list items set 2 d",
+ "list items get 2",
+ "var result = %out",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "d");
+ }
+
+ [TestMethod]
+ public void ListRemoveAndLengthTest()
+ {
+ List lines =
+ [
+ "list items new",
+ "list items add a",
+ "list items add b",
+ "list items add c",
+ "list items remove 1",
+ "list items length",
+ "var len = %out",
+ "${len}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "2");
+ }
+
+ [TestMethod]
+ public void ListClearTest()
+ {
+ List lines =
+ [
+ "list items new",
+ "list items add a",
+ "list items clear",
+ "list items length",
+ "var len = %out",
+ "${len}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "0");
+ }
+
+ [TestMethod]
+ public void ListDeleteTest()
+ {
+ List lines =
+ [
+ "list items new",
+ "list items delete",
+ "list items length"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "List \"items\" not found");
+ }
+
+ [TestMethod]
+ public void ListMissingFailsTest()
+ {
+ List lines =
+ [
+ "list missing get 0"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "List \"missing\" not found");
+ }
+
+ [TestMethod]
+ public void ListInvalidIndexFailsTest()
+ {
+ List lines =
+ [
+ "list items new",
+ "list items add a",
+ "list items get 3"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Index 3 out of range");
+ }
+
+ [TestMethod]
+ public void ListInvalidSyntaxFailsTest()
+ {
+ List lines =
+ [
+ "list items add"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement");
+ }
+
+ [TestMethod]
+ public void ListScopeInsideFunctionTest()
+ {
+ List lines =
+ [
+ "goto main",
+ "func make:",
+ "list items new",
+ "list items add x",
+ "list items get 0",
+ "push_out %out",
+ "return",
+ "label main:",
+ "call make",
+ "var result = %out",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "x");
+ }
+
+ [TestMethod]
+ public void ListAddWithSpacesTest()
+ {
+ List lines =
+ [
+ "list items new",
+ "list items add hello~spcworld",
+ "list items get 0",
+ "var result = %out eval",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "hello world");
+ }
+}
diff --git a/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs b/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
index 98a093e..7bd07a3 100644
--- a/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/ProcessingStatementsTests.cs
@@ -132,7 +132,9 @@ public class ProcessingStatementsTests
[
"global result = 0",
"global result = 1 task",
- "sleep 50",
+ "while ${result} == 0:",
+ "sleep 10",
+ "end_while",
"${result}"
];
diff --git a/YesNt.Interpreter/Runtime/FunctionScope.cs b/YesNt.Interpreter/Runtime/FunctionScope.cs
index cbae505..4bea9c6 100644
--- a/YesNt.Interpreter/Runtime/FunctionScope.cs
+++ b/YesNt.Interpreter/Runtime/FunctionScope.cs
@@ -6,7 +6,8 @@ internal class FunctionScope(int callerLine, Stack arguments)
{
public int CallerLine { get; } = callerLine;
public Dictionary Variables { get; } = [];
+ public Dictionary> Lists { get; } = [];
public Dictionary Labels { get; } = [];
public Stack Arguments { get; } = arguments;
public Stack Results { get; } = new();
-}
\ No newline at end of file
+}
diff --git a/YesNt.Interpreter/Runtime/RuntimeInformation.cs b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
index 719e010..57d61d6 100644
--- a/YesNt.Interpreter/Runtime/RuntimeInformation.cs
+++ b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
@@ -15,6 +15,7 @@ internal sealed class RuntimeInformation
private static int internalTaskId = 0;
private readonly Dictionary topVariables = [];
+ private readonly Dictionary> topLists = [];
private readonly Dictionary topLabels = [];
private RuntimeInformation parentRuntimeInformation;
private int taskId = 0;
@@ -43,6 +44,7 @@ internal sealed class RuntimeInformation
}
public Dictionary Variables => FunctionCallStack.Count == 0 ? topVariables : FunctionCallStack.Peek().Variables;
+ public Dictionary> Lists => FunctionCallStack.Count == 0 ? topLists : FunctionCallStack.Peek().Lists;
public Dictionary Labels => FunctionCallStack.Count == 0 ? topLabels : FunctionCallStack.Peek().Labels;
@@ -148,6 +150,7 @@ internal sealed class RuntimeInformation
public void Reset()
{
topVariables.Clear();
+ topLists.Clear();
Lines.Clear();
GlobalVariables.Clear();
Labels.Clear();
@@ -176,4 +179,4 @@ internal sealed class RuntimeInformation
{
Exit($"Terminated by parent task", stopAllTasks);
}
-}
\ No newline at end of file
+}
diff --git a/YesNt.Interpreter/Statements/ListStatements.cs b/YesNt.Interpreter/Statements/ListStatements.cs
new file mode 100644
index 0000000..bb2e810
--- /dev/null
+++ b/YesNt.Interpreter/Statements/ListStatements.cs
@@ -0,0 +1,274 @@
+using System;
+using System.Collections.Generic;
+
+using YesNt.Interpreter.Attributes;
+using YesNt.Interpreter.Enums;
+using YesNt.Interpreter.Runtime;
+
+namespace YesNt.Interpreter.Statements;
+
+internal class ListStatements : StatementRuntimeInformation
+{
+ [Statement("list", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkCyan, Separator = " new")]
+ public void Create(string args)
+ {
+ string[] parts = SplitTwo(args, " new");
+ if (parts is null)
+ {
+ return;
+ }
+
+ string name = parts[0];
+ if (!RuntimeInfo.Lists.ContainsKey(name))
+ {
+ RuntimeInfo.Lists.Add(name, []);
+ }
+ else
+ {
+ RuntimeInfo.Lists[name].Clear();
+ }
+ }
+
+ [Statement("list", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkCyan, Separator = " delete")]
+ public void Delete(string args)
+ {
+ string[] parts = SplitTwo(args, " delete");
+ if (parts is null)
+ {
+ return;
+ }
+
+ string name = parts[0];
+
+ if (!RuntimeInfo.Lists.ContainsKey(name))
+ {
+ RuntimeInfo.Exit($"List \"{name}\" not found", true);
+ return;
+ }
+
+ _ = RuntimeInfo.Lists.Remove(name);
+ }
+
+ [Statement("list", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkCyan, Separator = " clear")]
+ public void Clear(string args)
+ {
+ string[] parts = SplitTwo(args, " clear");
+ if (parts is null)
+ {
+ return;
+ }
+
+ if (!TryGetList(parts[0], out List list))
+ {
+ return;
+ }
+
+ list.Clear();
+ }
+
+ [Statement("list", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkCyan, Separator = " length")]
+ public void Length(string args)
+ {
+ string[] parts = SplitTwo(args, " length");
+ if (parts is null)
+ {
+ return;
+ }
+
+ if (!TryGetList(parts[0], out List list))
+ {
+ return;
+ }
+
+ RuntimeInfo.OutParametersStack.Clear();
+ RuntimeInfo.OutParametersStack.Push(list.Count.ToString());
+ }
+
+ [Statement("list", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkCyan, Separator = " add ")]
+ public void Add(string args)
+ {
+ string[] parts = SplitTwo(args, " add ");
+ if (parts is null)
+ {
+ return;
+ }
+
+ if (!TryGetList(parts[0], out List list))
+ {
+ return;
+ }
+
+ if (string.IsNullOrWhiteSpace(parts[1]))
+ {
+ RuntimeInfo.Exit("Invalid syntax", true);
+ return;
+ }
+
+ list.Add(parts[1].Trim());
+ }
+
+ [Statement("list", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkCyan, Separator = " get ")]
+ public void Get(string args)
+ {
+ string[] parts = SplitTwo(args, " get ");
+ if (parts is null)
+ {
+ return;
+ }
+
+ if (!TryGetList(parts[0], out List list))
+ {
+ return;
+ }
+
+ if (!TryParseIndex(parts[1], out int index, list.Count))
+ {
+ return;
+ }
+
+ RuntimeInfo.OutParametersStack.Clear();
+ RuntimeInfo.OutParametersStack.Push(list[index]);
+ }
+
+ [Statement("list", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkCyan, Separator = " remove ")]
+ public void Remove(string args)
+ {
+ string[] parts = SplitTwo(args, " remove ");
+ if (parts is null)
+ {
+ return;
+ }
+
+ if (!TryGetList(parts[0], out List list))
+ {
+ return;
+ }
+
+ if (!TryParseIndex(parts[1], out int index, list.Count))
+ {
+ return;
+ }
+
+ list.RemoveAt(index);
+ }
+
+ [Statement("list", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkCyan, Separator = " set ")]
+ public void Set(string args)
+ {
+ string[] parts = SplitTwo(args, " set ");
+ if (parts is null)
+ {
+ return;
+ }
+
+ if (!TryGetList(parts[0], out List list))
+ {
+ return;
+ }
+
+ string[] indexAndValue = SplitIndexAndValue(parts[1]);
+ if (indexAndValue is null)
+ {
+ return;
+ }
+
+ if (!TryParseIndex(indexAndValue[0], out int index, list.Count))
+ {
+ return;
+ }
+
+ list[index] = indexAndValue[1];
+ }
+
+ [Statement("list", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkCyan, Separator = " insert ")]
+ public void Insert(string args)
+ {
+ string[] parts = SplitTwo(args, " insert ");
+ if (parts is null)
+ {
+ return;
+ }
+
+ if (!TryGetList(parts[0], out List list))
+ {
+ return;
+ }
+
+ string[] indexAndValue = SplitIndexAndValue(parts[1]);
+ if (indexAndValue is null)
+ {
+ return;
+ }
+
+ if (!TryParseIndex(indexAndValue[0], out int index, list.Count + 1))
+ {
+ return;
+ }
+
+ list.Insert(index, indexAndValue[1]);
+ }
+
+ private string[] SplitTwo(string input, string separator)
+ {
+ string[] parts = input.Split(separator, 2, StringSplitOptions.None);
+ if (parts.Length != 2)
+ {
+ RuntimeInfo.Exit("Invalid syntax", true);
+ return null;
+ }
+
+ parts[0] = parts[0].Trim();
+ parts[1] = parts[1].Trim();
+
+ if (string.IsNullOrWhiteSpace(parts[0]))
+ {
+ RuntimeInfo.Exit("Invalid syntax", true);
+ return null;
+ }
+
+ return parts;
+ }
+
+ private bool TryGetList(string name, out List list)
+ {
+ if (!RuntimeInfo.Lists.TryGetValue(name, out list))
+ {
+ RuntimeInfo.Exit($"List \"{name}\" not found", true);
+ return false;
+ }
+
+ return true;
+ }
+
+ private string[] SplitIndexAndValue(string input)
+ {
+ string[] parts = input.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
+ if (parts.Length != 2)
+ {
+ RuntimeInfo.Exit("Invalid syntax", true);
+ return null;
+ }
+
+ parts[0] = parts[0].Trim();
+ parts[1] = parts[1].Trim();
+ return parts;
+ }
+
+ private bool TryParseIndex(string rawIndex, out int index, int maxExclusive)
+ {
+ bool success = int.TryParse(rawIndex.Trim(), out index);
+ if (!success)
+ {
+ RuntimeInfo.Exit($"\"{rawIndex}\" is not a valid index", true);
+ return false;
+ }
+
+ if (index < 0 || index >= maxExclusive)
+ {
+ RuntimeInfo.Exit($"Index {index} out of range", true);
+ return false;
+ }
+
+ return true;
+ }
+}
From 7f58fb4aaf511aca6f96f1e902734ff535506c11 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 16:01:23 +0100
Subject: [PATCH 30/73] Add step debug mode and refactor command handling for
run/debug
---
YesNt.CodeEditor/Editor.cs | 11 +++-
YesNt.CodeEditor/InputHandler.cs | 102 +++++++++++++++++++++++--------
2 files changed, 85 insertions(+), 28 deletions(-)
diff --git a/YesNt.CodeEditor/Editor.cs b/YesNt.CodeEditor/Editor.cs
index f3f7698..f2b2973 100644
--- a/YesNt.CodeEditor/Editor.cs
+++ b/YesNt.CodeEditor/Editor.cs
@@ -20,6 +20,7 @@ internal class TextEditor
public Point CursorPosition { get; } = new(0, 0);
public Mode EditMode { get; set; } = Mode.Command;
public string CurrentPath { get; set; } = string.Empty;
+ public bool IsStepDebugMode { get; set; }
public TextEditor(string path) : this()
{
@@ -241,6 +242,14 @@ internal class TextEditor
{
Console.Write(output);
}
+
+ if (IsStepDebugMode && e is not null && !e.IsTask)
+ {
+ Console.ForegroundColor = ConsoleColor.DarkGray;
+ Console.WriteLine("[Step] Press any key for next line (Ctrl+C to stop)...");
+ Console.ForegroundColor = ConsoleColor.Gray;
+ _ = Console.ReadKey(true);
+ }
}
}
@@ -279,4 +288,4 @@ internal enum Mode
Edit,
Command,
Debug
-}
\ No newline at end of file
+}
diff --git a/YesNt.CodeEditor/InputHandler.cs b/YesNt.CodeEditor/InputHandler.cs
index 924e5b2..bf24a9e 100644
--- a/YesNt.CodeEditor/InputHandler.cs
+++ b/YesNt.CodeEditor/InputHandler.cs
@@ -225,36 +225,18 @@ internal class InputHandler(TextEditor textEditor)
break;
case "run":
- if (textEditor.Save(input, true))
- {
- textEditor.EditMode = Mode.Debug;
- Console.Clear();
- Console.CursorVisible = true;
- textEditor.YesNtInterpreter.Execute(textEditor.CurrentPath);
- while (Console.KeyAvailable)
- {
- _ = Console.ReadKey(true);
- }
- _ = Console.ReadKey();
- WriteStatus(string.Empty);
- textEditor.EditMode = Mode.Command;
- }
+ ExecuteWithDebugScreen(input, false, false);
break;
case "debug":
- if (textEditor.Save(input, true))
+ if (TryParseDebugCommand(input, out bool stepMode, out string parsedPath))
{
- textEditor.EditMode = Mode.Debug;
- Console.Clear();
- Console.CursorVisible = true;
- textEditor.YesNtInterpreter.Execute(textEditor.CurrentPath, true);
- while (Console.KeyAvailable)
- {
- _ = Console.ReadKey(true);
- }
- _ = Console.ReadKey();
- WriteStatus(string.Empty);
- textEditor.EditMode = Mode.Command;
+ string saveInput = string.IsNullOrWhiteSpace(parsedPath) ? "debug" : $"debug {parsedPath}";
+ ExecuteWithDebugScreen(saveInput, true, stepMode);
+ }
+ else
+ {
+ WriteStatus("Invalid arguments!");
}
break;
@@ -309,4 +291,70 @@ internal class InputHandler(TextEditor textEditor)
Console.SetCursorPosition(0, Console.WindowHeight - 1);
Console.Write(input + new string(' ', Console.WindowWidth - input.Length - 1));
}
-}
\ No newline at end of file
+
+ private static bool TryParseDebugCommand(string input, out bool stepMode, out string path)
+ {
+ stepMode = false;
+ path = string.Empty;
+
+ string[] parts = input.Split(' ', StringSplitOptions.RemoveEmptyEntries);
+ if (parts.Length == 0 || !parts[0].Equals("debug", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ for (int i = 1; i < parts.Length; i++)
+ {
+ string token = parts[i];
+ if (token.Equals("step", StringComparison.OrdinalIgnoreCase))
+ {
+ if (stepMode)
+ {
+ return false;
+ }
+
+ stepMode = true;
+ continue;
+ }
+
+ if (string.IsNullOrWhiteSpace(path))
+ {
+ path = token;
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ private void ExecuteWithDebugScreen(string saveInput, bool debugMode, bool stepMode)
+ {
+ if (textEditor.Save(saveInput, true))
+ {
+ textEditor.EditMode = Mode.Debug;
+ textEditor.IsStepDebugMode = stepMode;
+ Console.Clear();
+ Console.CursorVisible = true;
+
+ if (debugMode)
+ {
+ textEditor.YesNtInterpreter.Execute(textEditor.CurrentPath, true);
+ }
+ else
+ {
+ textEditor.YesNtInterpreter.Execute(textEditor.CurrentPath);
+ }
+
+ while (Console.KeyAvailable)
+ {
+ _ = Console.ReadKey(true);
+ }
+ _ = Console.ReadKey();
+ WriteStatus(string.Empty);
+ textEditor.IsStepDebugMode = false;
+ textEditor.EditMode = Mode.Command;
+ }
+ }
+}
From 86819900a02ad7f8854e9e495e561a22cf794bc7 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 16:21:49 +0100
Subject: [PATCH 31/73] Add string literal parsing with escapes and related
tests
---
SYNTAX_V2.md | 3 +
.../StringLiteralStatementsTests.cs | 71 +++++++++++++++++
.../Statements/StringLiteralStatements.cs | 78 +++++++++++++++++++
3 files changed, 152 insertions(+)
create mode 100644 YesNt.Interpreter.Tests/StringLiteralStatementsTests.cs
create mode 100644 YesNt.Interpreter/Statements/StringLiteralStatements.cs
diff --git a/SYNTAX_V2.md b/SYNTAX_V2.md
index 690e071..6669145 100644
--- a/SYNTAX_V2.md
+++ b/SYNTAX_V2.md
@@ -14,6 +14,8 @@ This document describes the current, word-based YesNt syntax.
- Statements are line-based.
- `# ...` remains a comment.
- Variable interpolation inside text uses `${name}`.
+- String literals use double quotes (`"..."`) with escapes like `\n`, `\t`, `\"`, `\\`.
+ Interpolation is not evaluated inside string literals.
- Function and label declarations are block markers with a trailing `:`.
- Conditions retain current evaluator expressions (for example: `a == b`, `x > 5`, `10 + 2 == 12`).
@@ -22,6 +24,7 @@ This document describes the current, word-based YesNt syntax.
```ynt
var name = world
func greet:
+print_line "Hello world"
print_line Hello ${name}
return
call greet
diff --git a/YesNt.Interpreter.Tests/StringLiteralStatementsTests.cs b/YesNt.Interpreter.Tests/StringLiteralStatementsTests.cs
new file mode 100644
index 0000000..e6ffcda
--- /dev/null
+++ b/YesNt.Interpreter.Tests/StringLiteralStatementsTests.cs
@@ -0,0 +1,71 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System.Collections.Generic;
+
+namespace YesNt.Interpreter.Tests;
+
+[TestClass]
+public class StringLiteralStatementsTests
+{
+ [TestMethod]
+ public void StringLiteralWithSpacesWorksTest()
+ {
+ List lines =
+ [
+ "var msg = \"hello world\"",
+ "${msg}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "hello world");
+ }
+
+ [TestMethod]
+ public void StringLiteralEscapesWorkTest()
+ {
+ List lines =
+ [
+ "var msg = \"a\\n\\t\\\"b\"",
+ "${msg}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "a\n\t\"b");
+ }
+
+ [TestMethod]
+ public void StringLiteralPreventsVariableInterpolationTest()
+ {
+ List lines =
+ [
+ "var x = hidden",
+ "print_line \"${x}\""
+ ];
+
+ YesNtAssert.ContainsDebugOutput(lines, "${x}");
+ }
+
+ [TestMethod]
+ public void StringLiteralWorksWithListAddTest()
+ {
+ List lines =
+ [
+ "list items new",
+ "list items add \"hello world\"",
+ "list items get 0",
+ "var result = %out",
+ "${result}"
+ ];
+
+ YesNtAssert.IsLastLineEqual(lines, "hello world");
+ }
+
+ [TestMethod]
+ public void UnterminatedStringLiteralFailsTest()
+ {
+ List lines =
+ [
+ "var msg = \"hello"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Invalid string literal");
+ }
+}
diff --git a/YesNt.Interpreter/Statements/StringLiteralStatements.cs b/YesNt.Interpreter/Statements/StringLiteralStatements.cs
new file mode 100644
index 0000000..c2d0971
--- /dev/null
+++ b/YesNt.Interpreter/Statements/StringLiteralStatements.cs
@@ -0,0 +1,78 @@
+using System.Text;
+
+using YesNt.Interpreter.Attributes;
+using YesNt.Interpreter.Enums;
+using YesNt.Interpreter.Runtime;
+using YesNt.Interpreter.Utilities;
+
+namespace YesNt.Interpreter.Statements;
+
+internal class StringLiteralStatements : StatementRuntimeInformation
+{
+ [Statement("\"", SearchMode.Contains, SpaceAround.None, System.ConsoleColor.DarkYellow, Priority = Priority.PreProcessing, KeepStatementInArgs = true)]
+ public void ParseStringLiterals(string args)
+ {
+ if (!args.Contains('"'))
+ {
+ return;
+ }
+
+ StringBuilder output = new StringBuilder(args.Length);
+
+ for (int i = 0; i < args.Length; i++)
+ {
+ char current = args[i];
+ if (current != '"')
+ {
+ _ = output.Append(current);
+ continue;
+ }
+
+ StringBuilder literal = new StringBuilder();
+ bool closed = false;
+ i++;
+
+ for (; i < args.Length; i++)
+ {
+ char ch = args[i];
+ if (ch == '\\' && i + 1 < args.Length)
+ {
+ i++;
+ _ = literal.Append(ParseEscape(args[i]));
+ continue;
+ }
+
+ if (ch == '"')
+ {
+ closed = true;
+ break;
+ }
+
+ _ = literal.Append(ch);
+ }
+
+ if (!closed)
+ {
+ RuntimeInfo.Exit("Invalid string literal", true);
+ return;
+ }
+
+ _ = output.Append(literal.ToString().ToSafeString());
+ }
+
+ RuntimeInfo.CurrentLine = output.ToString();
+ }
+
+ private static char ParseEscape(char escapeChar)
+ {
+ return escapeChar switch
+ {
+ 'n' => '\n',
+ 'r' => '\r',
+ 't' => '\t',
+ '"' => '"',
+ '\\' => '\\',
+ _ => escapeChar
+ };
+ }
+}
From e47f614e621f15c99657d5bdc9ac4ecf89450ff2 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 17:40:14 +0100
Subject: [PATCH 32/73] Convert import statement path from safe string before
combining paths
---
YesNt.Interpreter/Statements/ProcessingStatements.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/YesNt.Interpreter/Statements/ProcessingStatements.cs b/YesNt.Interpreter/Statements/ProcessingStatements.cs
index aa1e963..bd363f5 100644
--- a/YesNt.Interpreter/Statements/ProcessingStatements.cs
+++ b/YesNt.Interpreter/Statements/ProcessingStatements.cs
@@ -82,6 +82,7 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
[Statement("import", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Magenta)]
public void Import(string path)
{
+ path = path.FromSafeString();
path = Path.Combine(RuntimeInfo.WorkingDirectory, path);
if (string.IsNullOrEmpty(Path.GetExtension(path)))
From f411aa7433d106bdf061b890b3b91f2dcceeafd7 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 17:50:58 +0100
Subject: [PATCH 33/73] Add string highlighting with DarkYellow and make sure
variable coloring gets applied before others
---
YesNt.CodeEditor/SyntaxHighlighter.cs | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/YesNt.CodeEditor/SyntaxHighlighter.cs b/YesNt.CodeEditor/SyntaxHighlighter.cs
index 57b9bd2..2c8a3e7 100644
--- a/YesNt.CodeEditor/SyntaxHighlighter.cs
+++ b/YesNt.CodeEditor/SyntaxHighlighter.cs
@@ -36,6 +36,19 @@ internal partial class SyntaxHighlighter(ReadOnlyCollection
Date: Wed, 4 Mar 2026 18:00:08 +0100
Subject: [PATCH 34/73] Swap variable and string regex order and update
highlight colors to prevent highlighting glitches
---
YesNt.CodeEditor/SyntaxHighlighter.cs | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/YesNt.CodeEditor/SyntaxHighlighter.cs b/YesNt.CodeEditor/SyntaxHighlighter.cs
index 2c8a3e7..7b8daa1 100644
--- a/YesNt.CodeEditor/SyntaxHighlighter.cs
+++ b/YesNt.CodeEditor/SyntaxHighlighter.cs
@@ -36,19 +36,18 @@ internal partial class SyntaxHighlighter(ReadOnlyCollection
Date: Wed, 4 Mar 2026 18:12:08 +0100
Subject: [PATCH 35/73] Code cleanup
---
YesNt.Interpreter.Generator/StatementRegistryGenerator.cs | 4 ++--
YesNt.Interpreter.Tests/YesNtAssert.cs | 2 +-
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 4 ++--
YesNt.Interpreter/Utilities/FixedProcess.cs | 8 +++-----
YesNt.Interpreter/Utilities/StringExtentions.cs | 2 --
5 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs b/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs
index a228de1..dbf028f 100644
--- a/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs
+++ b/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs
@@ -1,10 +1,10 @@
+using Microsoft.CodeAnalysis;
+
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
-using Microsoft.CodeAnalysis;
-
namespace YesNt.Interpreter.Generator;
[Generator]
diff --git a/YesNt.Interpreter.Tests/YesNtAssert.cs b/YesNt.Interpreter.Tests/YesNtAssert.cs
index 25c86f3..75380e7 100644
--- a/YesNt.Interpreter.Tests/YesNtAssert.cs
+++ b/YesNt.Interpreter.Tests/YesNtAssert.cs
@@ -2,8 +2,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
-using System.Text.RegularExpressions;
using System.Text;
+using System.Text.RegularExpressions;
using System.Threading;
using YesNt.Interpreter.Runtime;
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index da6aa9a..28192bd 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -160,7 +160,7 @@ public class YesNtInterpreter
{
if (statementAttribute.SearchMode == SearchMode.StartOfLine && runtimeInfo.CurrentLine.StartsWith(name))
{
- string copyLine = statementAttribute.KeepStatementInArgs ? runtimeInfo.CurrentLine : runtimeInfo.CurrentLine.Remove(0, name.Length);
+ string copyLine = statementAttribute.KeepStatementInArgs ? runtimeInfo.CurrentLine : runtimeInfo.CurrentLine[name.Length..];
statement.Value.Invoke(copyLine);
statementFound = true;
}
@@ -172,7 +172,7 @@ public class YesNtInterpreter
}
else if (statementAttribute.SearchMode == SearchMode.EndOfLine && runtimeInfo.CurrentLine.EndsWith(name))
{
- string copyLine = statementAttribute.KeepStatementInArgs ? runtimeInfo.CurrentLine : runtimeInfo.CurrentLine.Remove(runtimeInfo.CurrentLine.Length - name.Length);
+ string copyLine = statementAttribute.KeepStatementInArgs ? runtimeInfo.CurrentLine : runtimeInfo.CurrentLine[..^name.Length];
statement.Value.Invoke(copyLine);
statementFound = true;
}
diff --git a/YesNt.Interpreter/Utilities/FixedProcess.cs b/YesNt.Interpreter/Utilities/FixedProcess.cs
index 1117d27..28b401a 100644
--- a/YesNt.Interpreter/Utilities/FixedProcess.cs
+++ b/YesNt.Interpreter/Utilities/FixedProcess.cs
@@ -170,11 +170,9 @@ internal class AsyncStreamReader : IDisposable
byteBuffer = null;
charBuffer = null;
}
- if (eofEvent != null)
- {
- eofEvent.Close();
- eofEvent = null;
- }
+
+ eofEvent?.Close();
+ eofEvent = null;
}
private void Init(Stream stream, UserCallBack callback, Encoding encoding, int bufferSize)
diff --git a/YesNt.Interpreter/Utilities/StringExtentions.cs b/YesNt.Interpreter/Utilities/StringExtentions.cs
index 49d00f9..a28f1ea 100644
--- a/YesNt.Interpreter/Utilities/StringExtentions.cs
+++ b/YesNt.Interpreter/Utilities/StringExtentions.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Text;
@@ -30,7 +29,6 @@ public static class StringExtensions
{"", "~emp" },
};
- [SuppressMessage("Minor Code Smell", "S3963:\"static\" fields should be initialized inline", Justification = "Doesn't work because it throws a TypeInitializationException")]
static StringExtensions()
{
reverseReplacementRules = ReplacementRules.ToDictionary(x => x.Value, x => x.Key);
From 8e0abf155a8662c0541662a2f241c431dd374216 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 19:40:46 +0100
Subject: [PATCH 36/73] Make YesNtInterpreter usable as a library and add
AddStatement method to be able to define custom statement
---
YesNt-Interpreter.sln | 14 ++++++++++
YesNt.Interpreter.App/Program.cs | 14 ++++++++++
.../YesNt.Interpreter.App.csproj | 13 ++++++++++
.../Attributes/StatementAttribute.cs | 6 ++---
.../Attributes/StaticStatementAttribute.cs | 2 +-
YesNt.Interpreter/Enums/Priority.cs | 2 +-
YesNt.Interpreter/Program.cs | 26 ++++++++++++-------
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 19 ++++++++++++++
YesNt.Interpreter/YesNt.Interpreter.csproj | 2 +-
9 files changed, 83 insertions(+), 15 deletions(-)
create mode 100644 YesNt.Interpreter.App/Program.cs
create mode 100644 YesNt.Interpreter.App/YesNt.Interpreter.App.csproj
diff --git a/YesNt-Interpreter.sln b/YesNt-Interpreter.sln
index b2c2492..8e36ce1 100644
--- a/YesNt-Interpreter.sln
+++ b/YesNt-Interpreter.sln
@@ -14,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YesNt.Interpreter.Tests", "YesNt.Interpreter.Tests\YesNt.Interpreter.Tests.csproj", "{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YesNt.Interpreter.App", "YesNt.Interpreter.App\YesNt.Interpreter.App.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YesNt.Interpreter.Generator", "YesNt.Interpreter.Generator\YesNt.Interpreter.Generator.csproj", "{85AAB233-9C4D-4B42-8117-00010958DD1D}"
EndProject
Global
@@ -62,6 +64,18 @@ Global
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Release|x64.Build.0 = Release|x64
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Release|x86.ActiveCfg = Release|Any CPU
{2F95DCA7-3E43-4F2E-8FB2-067F0EC962B1}.Release|x86.Build.0 = Release|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.ActiveCfg = Debug|x64
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.Build.0 = Debug|x64
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.Build.0 = Debug|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.ActiveCfg = Release|x64
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.Build.0 = Release|x64
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.ActiveCfg = Release|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.Build.0 = Release|Any CPU
{85AAB233-9C4D-4B42-8117-00010958DD1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85AAB233-9C4D-4B42-8117-00010958DD1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85AAB233-9C4D-4B42-8117-00010958DD1D}.Debug|x64.ActiveCfg = Debug|Any CPU
diff --git a/YesNt.Interpreter.App/Program.cs b/YesNt.Interpreter.App/Program.cs
new file mode 100644
index 0000000..61311f7
--- /dev/null
+++ b/YesNt.Interpreter.App/Program.cs
@@ -0,0 +1,14 @@
+using System;
+
+using YesNt.Interpreter.Runtime;
+
+if (args.Length == 1)
+{
+ YesNtInterpreter interpreter = new YesNtInterpreter();
+ interpreter.Initialize();
+ interpreter.Execute(args[0]);
+}
+else
+{
+ Console.WriteLine("No path specified!");
+}
diff --git a/YesNt.Interpreter.App/YesNt.Interpreter.App.csproj b/YesNt.Interpreter.App/YesNt.Interpreter.App.csproj
new file mode 100644
index 0000000..018aab7
--- /dev/null
+++ b/YesNt.Interpreter.App/YesNt.Interpreter.App.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net8.0
+ Exe
+ AnyCPU;x64
+
+
+
+
+
+
+
diff --git a/YesNt.Interpreter/Attributes/StatementAttribute.cs b/YesNt.Interpreter/Attributes/StatementAttribute.cs
index 999c9e8..b2aabf4 100644
--- a/YesNt.Interpreter/Attributes/StatementAttribute.cs
+++ b/YesNt.Interpreter/Attributes/StatementAttribute.cs
@@ -5,7 +5,7 @@ using YesNt.Interpreter.Enums;
namespace YesNt.Interpreter.Attributes;
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
-internal class StatementAttribute : Attribute
+public class StatementAttribute : Attribute
{
public string Name { get; }
public SearchMode SearchMode { get; }
@@ -17,7 +17,7 @@ internal class StatementAttribute : Attribute
public bool IgnoreSyntaxHighlighting { get; }
public string Separator { get; set; }
- internal StatementAttribute(string name, SearchMode searchMode, SpaceAround spaceAround, ConsoleColor color)
+ public StatementAttribute(string name, SearchMode searchMode, SpaceAround spaceAround, ConsoleColor color)
{
Name = name;
SearchMode = searchMode;
@@ -25,7 +25,7 @@ internal class StatementAttribute : Attribute
Color = color;
}
- internal StatementAttribute(string name, SearchMode searchMode, SpaceAround spaceAround)
+ public StatementAttribute(string name, SearchMode searchMode, SpaceAround spaceAround)
{
Name = name;
SearchMode = searchMode;
diff --git a/YesNt.Interpreter/Attributes/StaticStatementAttribute.cs b/YesNt.Interpreter/Attributes/StaticStatementAttribute.cs
index f0c5a5a..59f80e3 100644
--- a/YesNt.Interpreter/Attributes/StaticStatementAttribute.cs
+++ b/YesNt.Interpreter/Attributes/StaticStatementAttribute.cs
@@ -5,7 +5,7 @@ using YesNt.Interpreter.Enums;
namespace YesNt.Interpreter.Attributes;
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
-internal class StaticStatementAttribute : Attribute
+public class StaticStatementAttribute : Attribute
{
public bool ExecuteInSearchMode { get; set; }
public Priority Priority { get; set; } = Priority.Normal;
diff --git a/YesNt.Interpreter/Enums/Priority.cs b/YesNt.Interpreter/Enums/Priority.cs
index acb372b..eb8353d 100644
--- a/YesNt.Interpreter/Enums/Priority.cs
+++ b/YesNt.Interpreter/Enums/Priority.cs
@@ -1,6 +1,6 @@
namespace YesNt.Interpreter.Enums;
-internal enum Priority
+public enum Priority
{
PreProcessing,
Highest,
diff --git a/YesNt.Interpreter/Program.cs b/YesNt.Interpreter/Program.cs
index ccbba14..1582b6b 100644
--- a/YesNt.Interpreter/Program.cs
+++ b/YesNt.Interpreter/Program.cs
@@ -1,14 +1,22 @@
-using System;
+using System;
using YesNt.Interpreter.Runtime;
-if (args.Length == 1)
+namespace YesNt.Interpreter;
+
+internal static class Program
{
- YesNtInterpreter interpreter = new YesNtInterpreter();
- interpreter.Initialize();
- interpreter.Execute(args[0]);
+ internal static void Main(string[] args)
+ {
+ if (args.Length == 1)
+ {
+ YesNtInterpreter interpreter = new YesNtInterpreter();
+ interpreter.Initialize();
+ interpreter.Execute(args[0]);
+ }
+ else
+ {
+ Console.WriteLine("No path specified!");
+ }
+ }
}
-else
-{
- Console.WriteLine("No path specified!");
-}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index 28192bd..65b5c47 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -41,6 +41,25 @@ public class YesNtInterpreter
}
}
+ public void AddStatement(StatementAttribute attribute, Action handler)
+ {
+ statements[attribute] = handler;
+ statements = statements
+ .OrderBy(s => s.Key.Priority)
+ .ThenByDescending(s => s.Key.Name.Length)
+ .ToDictionary(x => x.Key, x => x.Value);
+ }
+
+ public void AddStatement(string name, SearchMode searchMode, SpaceAround spaceAround, Action handler)
+ {
+ AddStatement(new StatementAttribute(name, searchMode, spaceAround), handler);
+ }
+
+ public void AddStatement(string name, SearchMode searchMode, SpaceAround spaceAround, ConsoleColor consoleColor, Action handler)
+ {
+ AddStatement(new StatementAttribute(name, searchMode, spaceAround, consoleColor), handler);
+ }
+
public void Stop()
{
runtimeInfo.Exit("Terminated by external process", true);
diff --git a/YesNt.Interpreter/YesNt.Interpreter.csproj b/YesNt.Interpreter/YesNt.Interpreter.csproj
index f6e5bb2..67e7926 100644
--- a/YesNt.Interpreter/YesNt.Interpreter.csproj
+++ b/YesNt.Interpreter/YesNt.Interpreter.csproj
@@ -4,7 +4,7 @@
net8.0
YesNt.Interpreter
- Exe
+ Library
AnyCPU;x64
From b2fdd9c8419b0275356fdbf4cd5c41fc7bfe3a9d Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 19:41:14 +0100
Subject: [PATCH 37/73] Remove Initialize calls and add AddStatement tests
---
YesNt.CodeEditor/Editor.cs | 1 -
YesNt.Interpreter.App/Program.cs | 1 -
YesNt.Interpreter.Tests/AddStatementTests.cs | 220 ++++++++++++++++++
.../ConsoleStatementsTests.cs | 3 +-
YesNt.Interpreter.Tests/YesNtAssert.cs | 23 +-
YesNt.Interpreter/Program.cs | 1 -
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 14 +-
.../Statements/ProcessingStatements.cs | 3 +-
8 files changed, 250 insertions(+), 16 deletions(-)
create mode 100644 YesNt.Interpreter.Tests/AddStatementTests.cs
diff --git a/YesNt.CodeEditor/Editor.cs b/YesNt.CodeEditor/Editor.cs
index f2b2973..6bd5b21 100644
--- a/YesNt.CodeEditor/Editor.cs
+++ b/YesNt.CodeEditor/Editor.cs
@@ -32,7 +32,6 @@ internal class TextEditor
public TextEditor()
{
- YesNtInterpreter.Initialize();
YesNtInterpreter.OnDebugOutput += YesNtInterpreter_OnDebugOutput;
YesNtInterpreter.OnLineExecuted += YesNtInterpreter_OnLineExecuted;
syntaxHighlighter = new(YesNtInterpreter.StatementInformation);
diff --git a/YesNt.Interpreter.App/Program.cs b/YesNt.Interpreter.App/Program.cs
index 61311f7..ccd2ec9 100644
--- a/YesNt.Interpreter.App/Program.cs
+++ b/YesNt.Interpreter.App/Program.cs
@@ -5,7 +5,6 @@ using YesNt.Interpreter.Runtime;
if (args.Length == 1)
{
YesNtInterpreter interpreter = new YesNtInterpreter();
- interpreter.Initialize();
interpreter.Execute(args[0]);
}
else
diff --git a/YesNt.Interpreter.Tests/AddStatementTests.cs b/YesNt.Interpreter.Tests/AddStatementTests.cs
new file mode 100644
index 0000000..6b4f6cd
--- /dev/null
+++ b/YesNt.Interpreter.Tests/AddStatementTests.cs
@@ -0,0 +1,220 @@
+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;
+
+[TestClass]
+public class AddStatementTests
+{
+ [TestMethod]
+ public void AddStatementStartOfLineExecutesHandlerTest()
+ {
+ List lines =
+ [
+ "my_command hello"
+ ];
+
+ string? capturedArgs = null;
+
+ YesNtAssert.GetLastLineWithSetup(lines, interpreter =>
+ {
+ interpreter.AddStatement("my_command", SearchMode.StartOfLine, SpaceAround.End, args =>
+ {
+ capturedArgs = args;
+ });
+ });
+
+ Assert.AreEqual("hello", capturedArgs);
+ }
+
+ [TestMethod]
+ public void AddStatementConvenienceOverloadHandlerIsCalledTest()
+ {
+ List lines =
+ [
+ "custom_cmd world"
+ ];
+
+ bool handlerCalled = false;
+
+ YesNtAssert.GetLastLineWithSetup(lines, interpreter =>
+ {
+ interpreter.AddStatement("custom_cmd", SearchMode.StartOfLine, SpaceAround.End, _ =>
+ {
+ handlerCalled = true;
+ });
+ });
+
+ Assert.IsTrue(handlerCalled);
+ }
+
+ [TestMethod]
+ public void AddStatementAttributeOverloadHandlerIsCalledTest()
+ {
+ List lines =
+ [
+ "attr_cmd test"
+ ];
+
+ bool handlerCalled = false;
+
+ YesNtAssert.GetLastLineWithSetup(lines, interpreter =>
+ {
+ var attr = new StatementAttribute("attr_cmd", SearchMode.StartOfLine, SpaceAround.End);
+ interpreter.AddStatement(attr, _ =>
+ {
+ handlerCalled = true;
+ });
+ });
+
+ Assert.IsTrue(handlerCalled);
+ }
+
+ [TestMethod]
+ public void AddStatementExactSearchModeTest()
+ {
+ List lines =
+ [
+ "exact_cmd"
+ ];
+
+ bool handlerCalled = false;
+
+ YesNtAssert.GetLastLineWithSetup(lines, interpreter =>
+ {
+ interpreter.AddStatement("exact_cmd", SearchMode.Exact, SpaceAround.None, _ =>
+ {
+ handlerCalled = true;
+ });
+ });
+
+ Assert.IsTrue(handlerCalled);
+ }
+
+ [TestMethod]
+ public void AddStatementContainsSearchModeTest()
+ {
+ List lines =
+ [
+ "prefix ~mark~ suffix"
+ ];
+
+ bool handlerCalled = false;
+
+ YesNtAssert.GetLastLineWithSetup(lines, interpreter =>
+ {
+ interpreter.AddStatement(" ~mark~ ", SearchMode.Contains, SpaceAround.None, _ =>
+ {
+ handlerCalled = true;
+ });
+ });
+
+ Assert.IsTrue(handlerCalled);
+ }
+
+ [TestMethod]
+ public void AddStatementEndOfLineSearchModeTest()
+ {
+ List lines =
+ [
+ "some text !end"
+ ];
+
+ bool handlerCalled = false;
+
+ YesNtAssert.GetLastLineWithSetup(lines, interpreter =>
+ {
+ interpreter.AddStatement(" !end", SearchMode.EndOfLine, SpaceAround.None, _ =>
+ {
+ handlerCalled = true;
+ });
+ });
+
+ Assert.IsTrue(handlerCalled);
+ }
+
+ [TestMethod]
+ public void AddStatementReceivesCorrectArgsTest()
+ {
+ List lines =
+ [
+ "capture_cmd the quick brown fox"
+ ];
+
+ string? capturedArgs = null;
+
+ YesNtAssert.GetLastLineWithSetup(lines, interpreter =>
+ {
+ interpreter.AddStatement("capture_cmd", SearchMode.StartOfLine, SpaceAround.End, args =>
+ {
+ capturedArgs = args;
+ });
+ });
+
+ Assert.AreEqual("the quick brown fox", capturedArgs);
+ }
+
+ [TestMethod]
+ public void AddStatementWorksAlongsideBuiltinStatementsTest()
+ {
+ List lines =
+ [
+ "custom_log first",
+ "print_line second"
+ ];
+
+ bool customCalled = false;
+
+ YesNtAssert.ContainsDebugOutputWithSetup(lines, "second", interpreter =>
+ {
+ interpreter.AddStatement("custom_log", SearchMode.StartOfLine, SpaceAround.End, _ =>
+ {
+ customCalled = true;
+ });
+ });
+
+ Assert.IsTrue(customCalled);
+ }
+
+ [TestMethod]
+ public void AddStatementUnknownStatementFailsTest()
+ {
+ List lines =
+ [
+ "unknown_command foo"
+ ];
+
+ YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement");
+ }
+
+ [TestMethod]
+ public void AddStatementWithHighPriorityRunsBeforeNormalTest()
+ {
+ List lines =
+ [
+ "priority_cmd arg"
+ ];
+
+ int callOrder = 0;
+ int highPriorityOrder = -1;
+ int normalPriorityOrder = -1;
+
+ YesNtAssert.GetLastLineWithSetup(lines, interpreter =>
+ {
+ interpreter.AddStatement(
+ new StatementAttribute("priority_cmd", SearchMode.StartOfLine, SpaceAround.End) { Priority = Priority.High },
+ _ => highPriorityOrder = callOrder++);
+
+ interpreter.AddStatement(
+ new StatementAttribute("priority_cmd", SearchMode.StartOfLine, SpaceAround.End) { Priority = Priority.Normal },
+ _ => normalPriorityOrder = callOrder++);
+ });
+
+ Assert.IsTrue(highPriorityOrder < normalPriorityOrder, "High priority statement should execute before Normal priority");
+ }
+}
diff --git a/YesNt.Interpreter.Tests/ConsoleStatementsTests.cs b/YesNt.Interpreter.Tests/ConsoleStatementsTests.cs
index fc076b7..1f9d6cd 100644
--- a/YesNt.Interpreter.Tests/ConsoleStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/ConsoleStatementsTests.cs
@@ -79,9 +79,8 @@ public class ConsoleStatementsTests
public void ReadKeyCanBeInterruptedByStopTest()
{
YesNtInterpreter interpreter = new YesNtInterpreter();
- interpreter.Initialize();
- AutoResetEvent onDone = new AutoResetEvent(false);
+ AutoResetEvent onDone= new AutoResetEvent(false);
StringBuilder output = new StringBuilder();
interpreter.OnDebugOutput += (s) => _ = output.Append(s);
diff --git a/YesNt.Interpreter.Tests/YesNtAssert.cs b/YesNt.Interpreter.Tests/YesNtAssert.cs
index 75380e7..09e53a5 100644
--- a/YesNt.Interpreter.Tests/YesNtAssert.cs
+++ b/YesNt.Interpreter.Tests/YesNtAssert.cs
@@ -67,10 +67,31 @@ internal static class YesNtAssert
StringAssert.Matches(value, new Regex(pattern));
}
+ public static void IsLastLineEqualWithSetup(List lines, string expected, Action setup, int timeout = 1000)
+ {
+ (DebugEventArgs? debugEventArgs, _) = ExecuteAndCapture(lines, timeout, setup);
+ Assert.AreEqual(expected, debugEventArgs?.CurrentLine);
+ }
+
+ public static void ContainsDebugOutputWithSetup(List lines, string expectedFragment, Action setup, int timeout = 1000)
+ {
+ (_, string debugOutput) = ExecuteAndCapture(lines, timeout, setup);
+ StringAssert.Contains(debugOutput, expectedFragment);
+ }
+
+ public static string? GetLastLineWithSetup(List lines, Action setup, int timeout = 1000)
+ {
+ (DebugEventArgs? debugEventArgs, _) = ExecuteAndCapture(lines, timeout, setup);
+ return debugEventArgs?.CurrentLine;
+ }
+
private static (DebugEventArgs? LastDebugEvent, string DebugOutput) ExecuteAndCapture(List lines, int timeout)
+ => ExecuteAndCapture(lines, timeout, setup: null);
+
+ private static (DebugEventArgs? LastDebugEvent, string DebugOutput) ExecuteAndCapture(List lines, int timeout, Action? setup)
{
YesNtInterpreter yesNtInterpreter = new YesNtInterpreter();
- yesNtInterpreter.Initialize();
+ setup?.Invoke(yesNtInterpreter);
AutoResetEvent onDone = new AutoResetEvent(false);
DebugEventArgs? debugEventArgs = null;
diff --git a/YesNt.Interpreter/Program.cs b/YesNt.Interpreter/Program.cs
index 1582b6b..330c6f7 100644
--- a/YesNt.Interpreter/Program.cs
+++ b/YesNt.Interpreter/Program.cs
@@ -11,7 +11,6 @@ internal static class Program
if (args.Length == 1)
{
YesNtInterpreter interpreter = new YesNtInterpreter();
- interpreter.Initialize();
interpreter.Execute(args[0]);
}
else
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index 65b5c47..c9ec6d3 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -60,21 +60,19 @@ public class YesNtInterpreter
AddStatement(new StatementAttribute(name, searchMode, spaceAround, consoleColor), handler);
}
- public void Stop()
+ public YesNtInterpreter()
{
- runtimeInfo.Exit("Terminated by external process", true);
- }
-
- public void Initialize()
- {
- statements.Clear();
- staticStatements.Clear();
GeneratedStatementRegistry.Register(runtimeInfo, out statements, out staticStatements);
runtimeInfo.OnDebugOutput += (s) => OnDebugOutput?.Invoke(s);
runtimeInfo.OnLineExecuted += (DebugEventArgs e) => OnLineExecuted?.Invoke(e);
}
+ public void Stop()
+ {
+ runtimeInfo.Exit("Terminated by external process", true);
+ }
+
public void Execute(string path, bool isDebugMode = false)
{
runtimeInfo.Reset();
diff --git a/YesNt.Interpreter/Statements/ProcessingStatements.cs b/YesNt.Interpreter/Statements/ProcessingStatements.cs
index bd363f5..31c524c 100644
--- a/YesNt.Interpreter/Statements/ProcessingStatements.cs
+++ b/YesNt.Interpreter/Statements/ProcessingStatements.cs
@@ -50,8 +50,7 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
_ = Task.Run(() =>
{
YesNtInterpreter interpreter = new YesNtInterpreter();
- interpreter.Initialize();
- interpreter.Execute(lines, RuntimeInfo.GlobalVariables, lineNumber, RuntimeInfo);
+ interpreter.Execute(lines, RuntimeInfo.GlobalVariables, lineNumber, RuntimeInfo);
});
RuntimeInfo.CurrentLine = string.Empty;
From 27f72f141380a04c8a26b61bf57655fec29b0e62 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 19:56:08 +0100
Subject: [PATCH 38/73] Remove Program.cs and its main entry point from
interpreter project
---
YesNt.Interpreter/Program.cs | 21 ---------------------
1 file changed, 21 deletions(-)
delete mode 100644 YesNt.Interpreter/Program.cs
diff --git a/YesNt.Interpreter/Program.cs b/YesNt.Interpreter/Program.cs
deleted file mode 100644
index 330c6f7..0000000
--- a/YesNt.Interpreter/Program.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-
-using YesNt.Interpreter.Runtime;
-
-namespace YesNt.Interpreter;
-
-internal static class Program
-{
- internal static void Main(string[] args)
- {
- if (args.Length == 1)
- {
- YesNtInterpreter interpreter = new YesNtInterpreter();
- interpreter.Execute(args[0]);
- }
- else
- {
- Console.WriteLine("No path specified!");
- }
- }
-}
From d00295516c647320b79cffb7849c37a4f1f3ef07 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 19:59:01 +0100
Subject: [PATCH 39/73] Merge setup parameter into ExecuteAndCapture method
with default value
---
YesNt.Interpreter.Tests/YesNtAssert.cs | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/YesNt.Interpreter.Tests/YesNtAssert.cs b/YesNt.Interpreter.Tests/YesNtAssert.cs
index 09e53a5..422f286 100644
--- a/YesNt.Interpreter.Tests/YesNtAssert.cs
+++ b/YesNt.Interpreter.Tests/YesNtAssert.cs
@@ -85,10 +85,7 @@ internal static class YesNtAssert
return debugEventArgs?.CurrentLine;
}
- private static (DebugEventArgs? LastDebugEvent, string DebugOutput) ExecuteAndCapture(List lines, int timeout)
- => ExecuteAndCapture(lines, timeout, setup: null);
-
- private static (DebugEventArgs? LastDebugEvent, string DebugOutput) ExecuteAndCapture(List lines, int timeout, Action? setup)
+ private static (DebugEventArgs? LastDebugEvent, string DebugOutput) ExecuteAndCapture(List lines, int timeout, Action? setup = null)
{
YesNtInterpreter yesNtInterpreter = new YesNtInterpreter();
setup?.Invoke(yesNtInterpreter);
From 3411bb88de1f5add2cb23791ef43939309da3d86 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 20:24:18 +0100
Subject: [PATCH 40/73] Refactor list statement methods to use empty array
checks over null checks
---
.../StatementRegistryGenerator.cs | 15 +++------
.../Statements/ListStatements.cs | 32 +++++++++----------
2 files changed, 20 insertions(+), 27 deletions(-)
diff --git a/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs b/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs
index dbf028f..8d296be 100644
--- a/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs
+++ b/YesNt.Interpreter.Generator/StatementRegistryGenerator.cs
@@ -225,19 +225,12 @@ public sealed class StatementRegistryGenerator : ISourceGenerator
};
}
- private sealed class MethodRegistration
+ private sealed class MethodRegistration(INamedTypeSymbol containingType, IMethodSymbol method, AttributeData attribute)
{
- public MethodRegistration(INamedTypeSymbol containingType, IMethodSymbol method, AttributeData attribute)
- {
- ContainingType = containingType;
- Method = method;
- Attribute = attribute;
- }
+ public INamedTypeSymbol ContainingType { get; } = containingType;
- public INamedTypeSymbol ContainingType { get; }
+ public IMethodSymbol Method { get; } = method;
- public IMethodSymbol Method { get; }
-
- public AttributeData Attribute { get; }
+ public AttributeData Attribute { get; } = attribute;
}
}
diff --git a/YesNt.Interpreter/Statements/ListStatements.cs b/YesNt.Interpreter/Statements/ListStatements.cs
index bb2e810..0159181 100644
--- a/YesNt.Interpreter/Statements/ListStatements.cs
+++ b/YesNt.Interpreter/Statements/ListStatements.cs
@@ -13,19 +13,19 @@ internal class ListStatements : StatementRuntimeInformation
public void Create(string args)
{
string[] parts = SplitTwo(args, " new");
- if (parts is null)
+ if (parts.Length == 0)
{
return;
}
string name = parts[0];
- if (!RuntimeInfo.Lists.ContainsKey(name))
+ if (!RuntimeInfo.Lists.TryGetValue(name, out List value))
{
RuntimeInfo.Lists.Add(name, []);
}
else
{
- RuntimeInfo.Lists[name].Clear();
+ value.Clear();
}
}
@@ -33,7 +33,7 @@ internal class ListStatements : StatementRuntimeInformation
public void Delete(string args)
{
string[] parts = SplitTwo(args, " delete");
- if (parts is null)
+ if (parts.Length == 0)
{
return;
}
@@ -53,7 +53,7 @@ internal class ListStatements : StatementRuntimeInformation
public void Clear(string args)
{
string[] parts = SplitTwo(args, " clear");
- if (parts is null)
+ if (parts.Length == 0)
{
return;
}
@@ -70,7 +70,7 @@ internal class ListStatements : StatementRuntimeInformation
public void Length(string args)
{
string[] parts = SplitTwo(args, " length");
- if (parts is null)
+ if (parts.Length == 0)
{
return;
}
@@ -88,7 +88,7 @@ internal class ListStatements : StatementRuntimeInformation
public void Add(string args)
{
string[] parts = SplitTwo(args, " add ");
- if (parts is null)
+ if (parts.Length == 0)
{
return;
}
@@ -111,7 +111,7 @@ internal class ListStatements : StatementRuntimeInformation
public void Get(string args)
{
string[] parts = SplitTwo(args, " get ");
- if (parts is null)
+ if (parts.Length == 0)
{
return;
}
@@ -134,7 +134,7 @@ internal class ListStatements : StatementRuntimeInformation
public void Remove(string args)
{
string[] parts = SplitTwo(args, " remove ");
- if (parts is null)
+ if (parts.Length == 0)
{
return;
}
@@ -156,7 +156,7 @@ internal class ListStatements : StatementRuntimeInformation
public void Set(string args)
{
string[] parts = SplitTwo(args, " set ");
- if (parts is null)
+ if (parts.Length == 0)
{
return;
}
@@ -167,7 +167,7 @@ internal class ListStatements : StatementRuntimeInformation
}
string[] indexAndValue = SplitIndexAndValue(parts[1]);
- if (indexAndValue is null)
+ if (indexAndValue.Length == 0)
{
return;
}
@@ -184,7 +184,7 @@ internal class ListStatements : StatementRuntimeInformation
public void Insert(string args)
{
string[] parts = SplitTwo(args, " insert ");
- if (parts is null)
+ if (parts.Length == 0)
{
return;
}
@@ -195,7 +195,7 @@ internal class ListStatements : StatementRuntimeInformation
}
string[] indexAndValue = SplitIndexAndValue(parts[1]);
- if (indexAndValue is null)
+ if (indexAndValue.Length == 0)
{
return;
}
@@ -214,7 +214,7 @@ internal class ListStatements : StatementRuntimeInformation
if (parts.Length != 2)
{
RuntimeInfo.Exit("Invalid syntax", true);
- return null;
+ return [];
}
parts[0] = parts[0].Trim();
@@ -223,7 +223,7 @@ internal class ListStatements : StatementRuntimeInformation
if (string.IsNullOrWhiteSpace(parts[0]))
{
RuntimeInfo.Exit("Invalid syntax", true);
- return null;
+ return [];
}
return parts;
@@ -246,7 +246,7 @@ internal class ListStatements : StatementRuntimeInformation
if (parts.Length != 2)
{
RuntimeInfo.Exit("Invalid syntax", true);
- return null;
+ return [];
}
parts[0] = parts[0].Trim();
From 10d5766873726e6a365d1e97e8355cb90ead85db Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 20:32:25 +0100
Subject: [PATCH 41/73] Centralize exit messages in ExitMessages class
---
.../VariableStatementsTests.cs | 2 +-
YesNt.Interpreter/Runtime/ExitMessages.cs | 36 +++++++++++++++++++
.../Runtime/RuntimeInformation.cs | 4 +--
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 12 +++----
.../Statements/CodeFlowStatements.cs | 36 +++++++++----------
.../Statements/ConsoleStatements.cs | 2 +-
.../Statements/FunctionStatements.cs | 24 ++++++-------
.../Statements/ListStatements.cs | 16 ++++-----
.../Statements/ProcessingStatements.cs | 8 ++---
.../Statements/StringLiteralStatements.cs | 2 +-
.../Statements/SystemStatements.cs | 8 ++---
.../Statements/VariableStatements.cs | 12 +++----
12 files changed, 99 insertions(+), 63 deletions(-)
create mode 100644 YesNt.Interpreter/Runtime/ExitMessages.cs
diff --git a/YesNt.Interpreter.Tests/VariableStatementsTests.cs b/YesNt.Interpreter.Tests/VariableStatementsTests.cs
index ed1f3ec..d7e07e3 100644
--- a/YesNt.Interpreter.Tests/VariableStatementsTests.cs
+++ b/YesNt.Interpreter.Tests/VariableStatementsTests.cs
@@ -88,7 +88,7 @@ public class VariableStatementsTests
"var a b = 1"
];
- YesNtAssert.ContainsTerminationMessage(lines, "Invalid Syntax");
+ YesNtAssert.ContainsTerminationMessage(lines, "Invalid syntax");
}
[TestMethod]
diff --git a/YesNt.Interpreter/Runtime/ExitMessages.cs b/YesNt.Interpreter/Runtime/ExitMessages.cs
new file mode 100644
index 0000000..a86b289
--- /dev/null
+++ b/YesNt.Interpreter/Runtime/ExitMessages.cs
@@ -0,0 +1,36 @@
+namespace YesNt.Interpreter.Runtime;
+
+internal static class ExitMessages
+{
+ internal const string InvalidSyntax = "Invalid syntax";
+ internal const string InvalidSyntaxColonRequired = "Invalid syntax. Statement must end with ':'";
+ internal const string InvalidOperation = "Invalid operation";
+ internal const string InvalidStatement = "Invalid statement";
+ internal const string InvalidStringLiteral = "Invalid string literal";
+ internal const string EndOfFile = "End of file";
+ internal const string TerminatedByExternalProcess = "Terminated by external process";
+ internal const string TerminatedByChildTask = "Terminated by child task";
+ internal const string TerminatedByParentTask = "Terminated by parent task";
+ internal const string PlannedTermination = "Planned termination by code";
+ internal const string PlannedTerminationCancelingTasks = "Planned termination by code. Canceling all tasks";
+ internal const string NoMatchingEndIf = "No matching end_if found";
+ internal const string NoMatchingEndWhile = "No matching end_while found";
+ internal const string NoMatchingWhile = "No matching while found";
+ internal const string NestedFunctionsNotAllowed = "Nested functions are not allowed";
+ internal const string NoOutArgumentInStack = "No out argument in stack";
+ internal const string StatementNotAllowedOutsideFunction = "Statement not allowed outside of function";
+ internal const string NoInArgumentInStack = "No in argument in stack";
+ internal const string NoFunctionInStack = "No function in stack";
+
+ internal static string LabelNotFound(string label) => $"Label \"{label}\" not found";
+ internal static string FunctionNotFound(string function) => $"Function \"{function}\" not found";
+ internal static string VariableNotFound(string variable) => $"Variable \"{variable}\" not found";
+ internal static string ListNotFound(string list) => $"List \"{list}\" not found";
+ internal static string InvalidIndex(string rawIndex) => $"\"{rawIndex}\" is not a valid index";
+ internal static string IndexOutOfRange(int index) => $"Index {index} out of range";
+ internal static string InvalidTimeoutValue(string value) => $"\"{value}\" is not a valid time-out value";
+ internal static string CouldNotLoadFile(string path) => $"Could not load file \"{path}\"";
+ internal static string CouldNotFindFile(string path) => $"Could not find file \"{path}\"";
+ internal static string CannotFindFile(string path) => $"Cannot find file \"{path}\".";
+ internal static string FailedToStart(string program, string message) => $"Failed to start \"{program}\". {message}";
+}
diff --git a/YesNt.Interpreter/Runtime/RuntimeInformation.cs b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
index 57d61d6..3e9a49c 100644
--- a/YesNt.Interpreter/Runtime/RuntimeInformation.cs
+++ b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
@@ -131,7 +131,7 @@ internal sealed class RuntimeInformation
{
StopAllTasks = true;
OnExit?.Invoke(message, StopAllTasks);
- parentRuntimeInformation?.Exit("Terminated by child task", true);
+ parentRuntimeInformation?.Exit(ExitMessages.TerminatedByChildTask, true);
}
}
@@ -177,6 +177,6 @@ internal sealed class RuntimeInformation
private void ParentRuntimeInformation_OnExit(string exitMessage, bool stopAllTasks)
{
- Exit($"Terminated by parent task", stopAllTasks);
+ Exit(ExitMessages.TerminatedByParentTask, stopAllTasks);
}
}
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index c9ec6d3..932735d 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -70,7 +70,7 @@ public class YesNtInterpreter
public void Stop()
{
- runtimeInfo.Exit("Terminated by external process", true);
+ runtimeInfo.Exit(ExitMessages.TerminatedByExternalProcess, true);
}
public void Execute(string path, bool isDebugMode = false)
@@ -106,7 +106,7 @@ public class YesNtInterpreter
runtimeInfo.GlobalVariables = globalVariables;
if (parentRuntimeInformation.StopAllTasks)
{
- runtimeInfo.Exit($"Parent task was terminated!", parentRuntimeInformation.StopAllTasks);
+ runtimeInfo.Exit(ExitMessages.TerminatedByParentTask, parentRuntimeInformation.StopAllTasks);
return;
}
Execute();
@@ -203,7 +203,7 @@ public class YesNtInterpreter
if (!statementFound)
{
- runtimeInfo.Exit("Invalid statement", true);
+ runtimeInfo.Exit(ExitMessages.InvalidStatement, true);
}
if (runtimeInfo.IsDebugMode && notSearchingLabel)
{
@@ -216,15 +216,15 @@ public class YesNtInterpreter
{
if (!string.IsNullOrWhiteSpace(runtimeInfo.SearchLabel))
{
- runtimeInfo.Exit($"Label \"{runtimeInfo.SearchLabel}\" not found", true);
+ runtimeInfo.Exit(ExitMessages.LabelNotFound(runtimeInfo.SearchLabel), true);
}
else if (!string.IsNullOrWhiteSpace(runtimeInfo.SearchFunction))
{
- runtimeInfo.Exit($"Function \"{runtimeInfo.SearchFunction}\" not found", true);
+ runtimeInfo.Exit(ExitMessages.FunctionNotFound(runtimeInfo.SearchFunction), true);
}
else
{
- runtimeInfo.Exit("End of file", false);
+ runtimeInfo.Exit(ExitMessages.EndOfFile, false);
}
if (runtimeInfo.IsDebugMode)
diff --git a/YesNt.Interpreter/Statements/CodeFlowStatements.cs b/YesNt.Interpreter/Statements/CodeFlowStatements.cs
index 1000b84..ab77405 100644
--- a/YesNt.Interpreter/Statements/CodeFlowStatements.cs
+++ b/YesNt.Interpreter/Statements/CodeFlowStatements.cs
@@ -32,7 +32,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
string[] parts = args.Split(" goto ", 2, StringSplitOptions.None);
if (parts.Length != 2)
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntax, true);
return;
}
@@ -43,7 +43,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
if (result is null)
{
- RuntimeInfo.Exit("Invalid operation", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidOperation, true);
return;
}
@@ -69,14 +69,14 @@ internal class CodeFlowStatements : StatementRuntimeInformation
string labelDeclaration = args.Trim();
if (!labelDeclaration.EndsWith(':'))
{
- RuntimeInfo.Exit("Invalid syntax. Statement must end with ':'", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntaxColonRequired, true);
return;
}
string key = NormalizeBlockName(labelDeclaration);
if (string.IsNullOrWhiteSpace(key))
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntax, true);
return;
}
@@ -120,7 +120,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
string[] parts = args.Split(" call ", 2, StringSplitOptions.None);
if (parts.Length != 2)
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntax, true);
return;
}
@@ -131,7 +131,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
if (result is null)
{
- RuntimeInfo.Exit("Invalid operation", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidOperation, true);
return;
}
@@ -159,7 +159,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
args = args.Trim();
if (!args.EndsWith(':'))
{
- RuntimeInfo.Exit("Invalid syntax. Statement must end with ':'", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntaxColonRequired, true);
return;
}
@@ -168,7 +168,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
if (result is null)
{
- RuntimeInfo.Exit("Invalid operation", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidOperation, true);
return;
}
@@ -180,7 +180,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
(int targetLine, _) = FindElseOrEndIf(RuntimeInfo.LineNumber);
if (targetLine < 0)
{
- RuntimeInfo.Exit("No matching end_if found", true);
+ RuntimeInfo.Exit(ExitMessages.NoMatchingEndIf, true);
return;
}
@@ -193,7 +193,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
int targetLine = FindEndIf(RuntimeInfo.LineNumber);
if (targetLine < 0)
{
- RuntimeInfo.Exit("No matching end_if found", true);
+ RuntimeInfo.Exit(ExitMessages.NoMatchingEndIf, true);
return;
}
@@ -211,7 +211,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
args = args.Trim();
if (!args.EndsWith(':'))
{
- RuntimeInfo.Exit("Invalid syntax. Statement must end with ':'", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntaxColonRequired, true);
return;
}
@@ -220,7 +220,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
if (result is null)
{
- RuntimeInfo.Exit("Invalid operation", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidOperation, true);
return;
}
@@ -232,7 +232,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
int endWhileLine = FindEndWhile(RuntimeInfo.LineNumber);
if (endWhileLine < 0)
{
- RuntimeInfo.Exit("No matching end_while found", true);
+ RuntimeInfo.Exit(ExitMessages.NoMatchingEndWhile, true);
return;
}
@@ -245,7 +245,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
int whileLine = FindWhile(RuntimeInfo.LineNumber);
if (whileLine < 0)
{
- RuntimeInfo.Exit("No matching while found", true);
+ RuntimeInfo.Exit(ExitMessages.NoMatchingWhile, true);
return;
}
@@ -260,7 +260,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
RuntimeInfo.IsInFunction = false;
if (RuntimeInfo.IsLocalSearch)
{
- RuntimeInfo.Exit($"Label \"{RuntimeInfo.SearchLabel}\" not found", true);
+ RuntimeInfo.Exit(ExitMessages.LabelNotFound(RuntimeInfo.SearchLabel), true);
}
return;
@@ -270,7 +270,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
RuntimeInfo.IsInFunction = false;
}
- RuntimeInfo.Exit("Planned termination by code", false);
+ RuntimeInfo.Exit(ExitMessages.PlannedTermination, false);
}
[Statement("abort_all", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red, ExecuteInSearchMode = true)]
@@ -281,7 +281,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
RuntimeInfo.IsInFunction = false;
if (RuntimeInfo.IsLocalSearch)
{
- RuntimeInfo.Exit($"Label \"{RuntimeInfo.SearchLabel}\" not found", true);
+ RuntimeInfo.Exit(ExitMessages.LabelNotFound(RuntimeInfo.SearchLabel), true);
}
return;
@@ -291,7 +291,7 @@ internal class CodeFlowStatements : StatementRuntimeInformation
RuntimeInfo.IsInFunction = false;
}
- RuntimeInfo.Exit("Planned termination by code. Canceling all tasks", true);
+ RuntimeInfo.Exit(ExitMessages.PlannedTerminationCancelingTasks, true);
}
[Statement("throw", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Red)]
diff --git a/YesNt.Interpreter/Statements/ConsoleStatements.cs b/YesNt.Interpreter/Statements/ConsoleStatements.cs
index 50264b4..9751305 100644
--- a/YesNt.Interpreter/Statements/ConsoleStatements.cs
+++ b/YesNt.Interpreter/Statements/ConsoleStatements.cs
@@ -37,7 +37,7 @@ internal class ConsoleStatements : StatementRuntimeInformation
string input = Console.ReadLine();
if (input is null)
{
- RuntimeInfo.Exit("Terminated by external process", true);
+ RuntimeInfo.Exit(ExitMessages.TerminatedByExternalProcess, true);
return;
}
args = args.ReplaceFirstOccurrence("%read_line ", input.ToSafeString() + " ");
diff --git a/YesNt.Interpreter/Statements/FunctionStatements.cs b/YesNt.Interpreter/Statements/FunctionStatements.cs
index d975a35..3c60faf 100644
--- a/YesNt.Interpreter/Statements/FunctionStatements.cs
+++ b/YesNt.Interpreter/Statements/FunctionStatements.cs
@@ -15,21 +15,21 @@ internal class FunctionStatements : StatementRuntimeInformation
{
if (RuntimeInfo.InternalIsInFunction)
{
- RuntimeInfo.Exit("Nested functions are not allowed", true);
+ RuntimeInfo.Exit(ExitMessages.NestedFunctionsNotAllowed, true);
return;
}
string functionDeclaration = args.Trim();
if (!functionDeclaration.EndsWith(':'))
{
- RuntimeInfo.Exit("Invalid syntax. Statement must end with ':'", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntaxColonRequired, true);
return;
}
string key = NormalizeBlockName(functionDeclaration);
if (string.IsNullOrWhiteSpace(key))
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntax, true);
return;
}
@@ -63,7 +63,7 @@ internal class FunctionStatements : StatementRuntimeInformation
{
if (RuntimeInfo.OutParametersStack.Count == 0)
{
- RuntimeInfo.Exit("No out argument in stack", true);
+ RuntimeInfo.Exit(ExitMessages.NoOutArgumentInStack, true);
return;
}
@@ -87,7 +87,7 @@ internal class FunctionStatements : StatementRuntimeInformation
string[] parts = args.Split(" with ", 2, StringSplitOptions.None);
if (parts.Length != 2)
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntax, true);
return;
}
@@ -118,7 +118,7 @@ internal class FunctionStatements : StatementRuntimeInformation
{
if (!RuntimeInfo.IsInFunction)
{
- RuntimeInfo.Exit("Statement not allowed outside of function", true);
+ RuntimeInfo.Exit(ExitMessages.StatementNotAllowedOutsideFunction, true);
return;
}
@@ -126,7 +126,7 @@ internal class FunctionStatements : StatementRuntimeInformation
{
if (RuntimeInfo.FunctionCallStack.Peek().Arguments.Count == 0)
{
- RuntimeInfo.Exit("No in argument in stack", true);
+ RuntimeInfo.Exit(ExitMessages.NoInArgumentInStack, true);
return;
}
@@ -141,7 +141,7 @@ internal class FunctionStatements : StatementRuntimeInformation
{
if (!RuntimeInfo.IsInFunction)
{
- RuntimeInfo.Exit("Statement not allowed outside of function", true);
+ RuntimeInfo.Exit(ExitMessages.StatementNotAllowedOutsideFunction, true);
return;
}
@@ -155,7 +155,7 @@ internal class FunctionStatements : StatementRuntimeInformation
{
if (!RuntimeInfo.IsInFunction)
{
- RuntimeInfo.Exit("Statement not allowed outside of function", true);
+ RuntimeInfo.Exit(ExitMessages.StatementNotAllowedOutsideFunction, true);
return;
}
@@ -167,7 +167,7 @@ internal class FunctionStatements : StatementRuntimeInformation
{
if (!RuntimeInfo.IsInFunction)
{
- RuntimeInfo.Exit("Statement not allowed outside of function", true);
+ RuntimeInfo.Exit(ExitMessages.StatementNotAllowedOutsideFunction, true);
return;
}
@@ -177,7 +177,7 @@ internal class FunctionStatements : StatementRuntimeInformation
if (RuntimeInfo.IsLocalSearch)
{
- RuntimeInfo.Exit($"Label \"{RuntimeInfo.SearchLabel}\" not found", true);
+ RuntimeInfo.Exit(ExitMessages.LabelNotFound(RuntimeInfo.SearchLabel), true);
}
return;
}
@@ -195,7 +195,7 @@ internal class FunctionStatements : StatementRuntimeInformation
}
else
{
- RuntimeInfo.Exit("No function in stack", true);
+ RuntimeInfo.Exit(ExitMessages.NoFunctionInStack, true);
}
}
diff --git a/YesNt.Interpreter/Statements/ListStatements.cs b/YesNt.Interpreter/Statements/ListStatements.cs
index 0159181..ca4b010 100644
--- a/YesNt.Interpreter/Statements/ListStatements.cs
+++ b/YesNt.Interpreter/Statements/ListStatements.cs
@@ -42,7 +42,7 @@ internal class ListStatements : StatementRuntimeInformation
if (!RuntimeInfo.Lists.ContainsKey(name))
{
- RuntimeInfo.Exit($"List \"{name}\" not found", true);
+ RuntimeInfo.Exit(ExitMessages.ListNotFound(name), true);
return;
}
@@ -100,7 +100,7 @@ internal class ListStatements : StatementRuntimeInformation
if (string.IsNullOrWhiteSpace(parts[1]))
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntax, true);
return;
}
@@ -213,7 +213,7 @@ internal class ListStatements : StatementRuntimeInformation
string[] parts = input.Split(separator, 2, StringSplitOptions.None);
if (parts.Length != 2)
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntax, true);
return [];
}
@@ -222,7 +222,7 @@ internal class ListStatements : StatementRuntimeInformation
if (string.IsNullOrWhiteSpace(parts[0]))
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntax, true);
return [];
}
@@ -233,7 +233,7 @@ internal class ListStatements : StatementRuntimeInformation
{
if (!RuntimeInfo.Lists.TryGetValue(name, out list))
{
- RuntimeInfo.Exit($"List \"{name}\" not found", true);
+ RuntimeInfo.Exit(ExitMessages.ListNotFound(name), true);
return false;
}
@@ -245,7 +245,7 @@ internal class ListStatements : StatementRuntimeInformation
string[] parts = input.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length != 2)
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntax, true);
return [];
}
@@ -259,13 +259,13 @@ internal class ListStatements : StatementRuntimeInformation
bool success = int.TryParse(rawIndex.Trim(), out index);
if (!success)
{
- RuntimeInfo.Exit($"\"{rawIndex}\" is not a valid index", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidIndex(rawIndex), true);
return false;
}
if (index < 0 || index >= maxExclusive)
{
- RuntimeInfo.Exit($"Index {index} out of range", true);
+ RuntimeInfo.Exit(ExitMessages.IndexOutOfRange(index), true);
return false;
}
diff --git a/YesNt.Interpreter/Statements/ProcessingStatements.cs b/YesNt.Interpreter/Statements/ProcessingStatements.cs
index 31c524c..3cfd3d9 100644
--- a/YesNt.Interpreter/Statements/ProcessingStatements.cs
+++ b/YesNt.Interpreter/Statements/ProcessingStatements.cs
@@ -23,7 +23,7 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
string res = Evaluator.Calculate(matches[i].Value);
if (res is null)
{
- RuntimeInfo.Exit("Invalid operation", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidOperation, true);
return;
}
args = args.FromSafeString().Replace(matches[i].Value, res);
@@ -65,7 +65,7 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
}
else
{
- RuntimeInfo.Exit($"\"{args}\" is not a valid time-out value", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidTimeoutValue(args), true);
}
}
@@ -104,12 +104,12 @@ internal partial class ProcessingStatements : StatementRuntimeInformation
}
catch
{
- RuntimeInfo.Exit($"Could not load file \"{path}\"", true);
+ RuntimeInfo.Exit(ExitMessages.CouldNotLoadFile(path), true);
}
}
else
{
- RuntimeInfo.Exit($"Could not find file \"{path}\"", true);
+ RuntimeInfo.Exit(ExitMessages.CouldNotFindFile(path), true);
}
}
diff --git a/YesNt.Interpreter/Statements/StringLiteralStatements.cs b/YesNt.Interpreter/Statements/StringLiteralStatements.cs
index c2d0971..e502a30 100644
--- a/YesNt.Interpreter/Statements/StringLiteralStatements.cs
+++ b/YesNt.Interpreter/Statements/StringLiteralStatements.cs
@@ -53,7 +53,7 @@ internal class StringLiteralStatements : StatementRuntimeInformation
if (!closed)
{
- RuntimeInfo.Exit("Invalid string literal", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidStringLiteral, true);
return;
}
diff --git a/YesNt.Interpreter/Statements/SystemStatements.cs b/YesNt.Interpreter/Statements/SystemStatements.cs
index a5d148d..31ccda0 100644
--- a/YesNt.Interpreter/Statements/SystemStatements.cs
+++ b/YesNt.Interpreter/Statements/SystemStatements.cs
@@ -33,11 +33,11 @@ internal class SystemStatements : StatementRuntimeInformation
}
catch (FileNotFoundException)
{
- RuntimeInfo.Exit($"Cannot find file \"{parts[0]}\".", false);
+ RuntimeInfo.Exit(ExitMessages.CannotFindFile(parts[0]), false);
}
catch (Win32Exception ex)
{
- RuntimeInfo.Exit($"Failed to start \"{parts[0]}\". {ex.Message}", false);
+ RuntimeInfo.Exit(ExitMessages.FailedToStart(parts[0], ex.Message), false);
}
// HACK: Clear line to avoid execution from another "exec" statement.
@@ -53,11 +53,11 @@ internal class SystemStatements : StatementRuntimeInformation
}
catch (FileNotFoundException)
{
- RuntimeInfo.Exit($"Cannot find file \"{input}\".", false);
+ RuntimeInfo.Exit(ExitMessages.CannotFindFile(input), false);
}
catch (Win32Exception ex)
{
- RuntimeInfo.Exit($"Failed to start \"{input}\". {ex.Message}", false);
+ RuntimeInfo.Exit(ExitMessages.FailedToStart(input, ex.Message), false);
}
}
diff --git a/YesNt.Interpreter/Statements/VariableStatements.cs b/YesNt.Interpreter/Statements/VariableStatements.cs
index b4cf6d8..f07f640 100644
--- a/YesNt.Interpreter/Statements/VariableStatements.cs
+++ b/YesNt.Interpreter/Statements/VariableStatements.cs
@@ -17,7 +17,7 @@ internal partial class VariableStatements : StatementRuntimeInformation
string key = parts[0].Trim();
if (key.Contains(' '))
{
- RuntimeInfo.Exit("Invalid Syntax", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntax, true);
}
if (RuntimeInfo.Variables.ContainsKey(key))
@@ -31,7 +31,7 @@ internal partial class VariableStatements : StatementRuntimeInformation
}
else
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntax, true);
}
}
@@ -44,7 +44,7 @@ internal partial class VariableStatements : StatementRuntimeInformation
string key = parts[0].Trim();
if (key.Contains(' '))
{
- RuntimeInfo.Exit("Invalid Syntax", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntax, true);
}
if (RuntimeInfo.GlobalVariables.ContainsKey(key))
@@ -58,7 +58,7 @@ internal partial class VariableStatements : StatementRuntimeInformation
}
else
{
- RuntimeInfo.Exit("Invalid syntax", true);
+ RuntimeInfo.Exit(ExitMessages.InvalidSyntax, true);
}
}
@@ -77,7 +77,7 @@ internal partial class VariableStatements : StatementRuntimeInformation
}
else
{
- RuntimeInfo.Exit($"Variable \"{key}\" not found", true);
+ RuntimeInfo.Exit(ExitMessages.VariableNotFound(key), true);
}
}
@@ -109,7 +109,7 @@ internal partial class VariableStatements : StatementRuntimeInformation
}
else if (!RuntimeInfo.IsSearching)
{
- RuntimeInfo.Exit($"Variable \"{varName}\" not found", true);
+ RuntimeInfo.Exit(ExitMessages.VariableNotFound(varName), true);
return;
}
}
From ac78afc12f72662fdc18b9fdc9a7d516a6ddc31b Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 20:34:45 +0100
Subject: [PATCH 42/73] Fix warnings
---
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index 932735d..02a3f65 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -17,8 +17,8 @@ public class YesNtInterpreter
public event Action OnDebugOutput;
private readonly RuntimeInformation runtimeInfo = new RuntimeInformation();
- private Dictionary> statements = [];
- private List> staticStatements = [];
+ private Dictionary> statements;
+ private readonly List> staticStatements;
public ReadOnlyCollection StatementInformation
{
@@ -65,7 +65,7 @@ public class YesNtInterpreter
GeneratedStatementRegistry.Register(runtimeInfo, out statements, out staticStatements);
runtimeInfo.OnDebugOutput += (s) => OnDebugOutput?.Invoke(s);
- runtimeInfo.OnLineExecuted += (DebugEventArgs e) => OnLineExecuted?.Invoke(e);
+ runtimeInfo.OnLineExecuted += e => OnLineExecuted?.Invoke(e);
}
public void Stop()
From a2f621d3f4fe2c05d50a1386b9db31a35ed4622b Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 20:44:06 +0100
Subject: [PATCH 43/73] Add XML docs
---
.../Attributes/StatementAttribute.cs | 57 ++++++++++++++
.../Attributes/StaticStatementAttribute.cs | 19 +++++
YesNt.Interpreter/Enums/Priority.cs | 16 ++++
YesNt.Interpreter/Enums/SearchMode.cs | 10 +++
YesNt.Interpreter/Enums/SpaceAround.cs | 10 +++
YesNt.Interpreter/Runtime/DebugEventArgs.cs | 21 +++++
YesNt.Interpreter/Runtime/ExitMessages.cs | 4 +
YesNt.Interpreter/Runtime/FunctionScope.cs | 15 ++++
YesNt.Interpreter/Runtime/Line.cs | 6 ++
.../Runtime/RuntimeInformation.cs | 7 ++
.../Runtime/StatementInformation.cs | 20 +++++
.../Runtime/StatementRuntimeInfo.cs | 10 +++
YesNt.Interpreter/Runtime/YesNtInterpreter.cs | 77 +++++++++++++++++++
YesNt.Interpreter/Utilities/Evaluator.cs | 18 +++++
YesNt.Interpreter/Utilities/FixedProcess.cs | 8 ++
.../Utilities/StringExtentions.cs | 49 ++++++++++++
16 files changed, 347 insertions(+)
diff --git a/YesNt.Interpreter/Attributes/StatementAttribute.cs b/YesNt.Interpreter/Attributes/StatementAttribute.cs
index b2aabf4..6f8f543 100644
--- a/YesNt.Interpreter/Attributes/StatementAttribute.cs
+++ b/YesNt.Interpreter/Attributes/StatementAttribute.cs
@@ -4,19 +4,69 @@ 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.
+///
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class StatementAttribute : Attribute
{
+ /// 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 colour 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; }
+ ///
+ /// Initialises a new with a syntax-highlight colour.
+ ///
+ /// The keyword that identifies this statement.
+ /// Where in the line the keyword is matched.
+ /// Which sides of the keyword require a surrounding space.
+ /// The colour used for syntax highlighting in the code editor.
public StatementAttribute(string name, SearchMode searchMode, SpaceAround spaceAround, ConsoleColor color)
{
Name = name;
@@ -25,6 +75,13 @@ public class StatementAttribute : Attribute
Color = color;
}
+ ///
+ /// Initialises a new without a syntax-highlight colour.
+ /// 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 StatementAttribute(string name, SearchMode searchMode, SpaceAround spaceAround)
{
Name = name;
diff --git a/YesNt.Interpreter/Attributes/StaticStatementAttribute.cs b/YesNt.Interpreter/Attributes/StaticStatementAttribute.cs
index 59f80e3..4ed6682 100644
--- a/YesNt.Interpreter/Attributes/StaticStatementAttribute.cs
+++ b/YesNt.Interpreter/Attributes/StaticStatementAttribute.cs
@@ -4,9 +4,28 @@ 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.
+///
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class StaticStatementAttribute : Attribute
{
+ ///
+ /// 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/YesNt.Interpreter/Enums/Priority.cs b/YesNt.Interpreter/Enums/Priority.cs
index eb8353d..8fbaf51 100644
--- a/YesNt.Interpreter/Enums/Priority.cs
+++ b/YesNt.Interpreter/Enums/Priority.cs
@@ -1,12 +1,28 @@
namespace YesNt.Interpreter.Enums;
+///
+/// Controls the execution order of statements. Lower values run first.
+///
public enum Priority
{
+ /// Runs before all other statements. Used for syntax pre-processing such as string literals.
PreProcessing,
+
+ /// Runs very early. Used for inline substitutions such as variable reads and parameter pops.
Highest,
+
+ /// Runs early.
VeryHigh,
+
+ /// Runs above normal order.
High,
+
+ /// Default execution order.
Normal,
+
+ /// Runs below normal order.
Low,
+
+ /// Runs last. Used for control-flow and variable definitions that depend on substitutions being complete.
VeryLow
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Enums/SearchMode.cs b/YesNt.Interpreter/Enums/SearchMode.cs
index 0226142..a13e749 100644
--- a/YesNt.Interpreter/Enums/SearchMode.cs
+++ b/YesNt.Interpreter/Enums/SearchMode.cs
@@ -1,9 +1,19 @@
namespace YesNt.Interpreter.Enums;
+///
+/// Determines where in a source line the interpreter searches for a statement keyword.
+///
public enum SearchMode
{
+ /// The keyword must appear at the beginning of the line.
StartOfLine,
+
+ /// The keyword must appear at the end of the line.
EndOfLine,
+
+ /// The keyword may appear anywhere in the line.
Contains,
+
+ /// The entire line must exactly match the keyword.
Exact
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Enums/SpaceAround.cs b/YesNt.Interpreter/Enums/SpaceAround.cs
index 0ee0990..c9e4292 100644
--- a/YesNt.Interpreter/Enums/SpaceAround.cs
+++ b/YesNt.Interpreter/Enums/SpaceAround.cs
@@ -1,9 +1,19 @@
namespace YesNt.Interpreter.Enums;
+///
+/// Specifies which sides of a statement keyword must be surrounded by a space when matching.
+///
public enum SpaceAround
{
+ /// A space is required both before and after the keyword.
StartEnd,
+
+ /// A space is required before the keyword only.
Start,
+
+ /// A space is required after the keyword only.
End,
+
+ /// No surrounding spaces are required.
None
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Runtime/DebugEventArgs.cs b/YesNt.Interpreter/Runtime/DebugEventArgs.cs
index 0f2d2fe..0a0a842 100644
--- a/YesNt.Interpreter/Runtime/DebugEventArgs.cs
+++ b/YesNt.Interpreter/Runtime/DebugEventArgs.cs
@@ -2,11 +2,32 @@
namespace YesNt.Interpreter.Runtime;
+///
+/// Provides per-line execution data raised through .
+///
public class DebugEventArgs : EventArgs
{
+ /// Gets the 1-based line number of the executed line within its source file.
public int LineNumber { get; internal set; }
+
+ ///
+ /// Gets the line content after all statement transformations have been applied
+ /// (e.g. after variable substitution). May differ from .
+ ///
public string CurrentLine { get; internal set; }
+
+ /// Gets the raw line content as it appeared in the source file.
public string OriginalLine { get; internal set; }
+
+ ///
+ /// Gets the task identifier of the task that executed this line, or 0 if the line
+ /// was executed on the main thread.
+ ///
public int TaskId { get; internal set; }
+
+ ///
+ /// Gets a value indicating whether this line was executed inside a background task
+ /// (spawned with the task statement).
+ ///
public bool IsTask { get; internal set; }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Runtime/ExitMessages.cs b/YesNt.Interpreter/Runtime/ExitMessages.cs
index a86b289..4d08b09 100644
--- a/YesNt.Interpreter/Runtime/ExitMessages.cs
+++ b/YesNt.Interpreter/Runtime/ExitMessages.cs
@@ -1,5 +1,9 @@
namespace YesNt.Interpreter.Runtime;
+///
+/// Central repository of all exit/error message strings used by .
+/// Keeping messages here ensures consistency and makes them easy to find or localise.
+///
internal static class ExitMessages
{
internal const string InvalidSyntax = "Invalid syntax";
diff --git a/YesNt.Interpreter/Runtime/FunctionScope.cs b/YesNt.Interpreter/Runtime/FunctionScope.cs
index 4bea9c6..e7c7abd 100644
--- a/YesNt.Interpreter/Runtime/FunctionScope.cs
+++ b/YesNt.Interpreter/Runtime/FunctionScope.cs
@@ -2,12 +2,27 @@
namespace YesNt.Interpreter.Runtime;
+///
+/// Represents one frame on the function call stack. Created when a call statement is
+/// executed and popped when the matching return is reached.
+///
internal class FunctionScope(int callerLine, Stack arguments)
{
+ /// Gets the zero-based line index to return to after this function completes.
public int CallerLine { get; } = callerLine;
+
+ /// Gets the local variable table for this function invocation.
public Dictionary Variables { get; } = [];
+
+ /// Gets the local list table for this function invocation.
public Dictionary> Lists { get; } = [];
+
+ /// Gets the local label table for this function invocation.
public Dictionary Labels { get; } = [];
+
+ /// Gets the stack of input arguments passed to this function via push_in.
public Stack Arguments { get; } = arguments;
+
+ /// Gets the stack of output values pushed via push_out, consumed by the caller via %out.
public Stack Results { get; } = new();
}
diff --git a/YesNt.Interpreter/Runtime/Line.cs b/YesNt.Interpreter/Runtime/Line.cs
index 7f3447d..fcb53af 100644
--- a/YesNt.Interpreter/Runtime/Line.cs
+++ b/YesNt.Interpreter/Runtime/Line.cs
@@ -1,10 +1,16 @@
namespace YesNt.Interpreter.Runtime;
+///
+/// Represents a single source line together with its location metadata.
+///
internal class Line(string content, string fileName, int lineNumber)
{
+ /// Gets or sets the raw text content of the line.
public string Content { get; set; } = content;
+ /// Gets or sets the name of the source file this line originated from.
public string FileName { get; set; } = fileName;
+ /// Gets or sets the zero-based line index within .
public int LineNumber { get; set; } = lineNumber;
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Runtime/RuntimeInformation.cs b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
index 3e9a49c..7ad1ca1 100644
--- a/YesNt.Interpreter/Runtime/RuntimeInformation.cs
+++ b/YesNt.Interpreter/Runtime/RuntimeInformation.cs
@@ -5,6 +5,13 @@ using YesNt.Interpreter.Utilities;
namespace YesNt.Interpreter.Runtime;
+///
+/// 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 task statement owns its own
+/// whose points back
+/// to the main execution context.
+///
internal sealed class RuntimeInformation
{
public event Action OnDebugOutput;
diff --git a/YesNt.Interpreter/Runtime/StatementInformation.cs b/YesNt.Interpreter/Runtime/StatementInformation.cs
index ab7e9a0..e08f4a6 100644
--- a/YesNt.Interpreter/Runtime/StatementInformation.cs
+++ b/YesNt.Interpreter/Runtime/StatementInformation.cs
@@ -4,12 +4,32 @@ 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 colour 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/YesNt.Interpreter/Runtime/StatementRuntimeInfo.cs b/YesNt.Interpreter/Runtime/StatementRuntimeInfo.cs
index 3a0c30a..a8b89e7 100644
--- a/YesNt.Interpreter/Runtime/StatementRuntimeInfo.cs
+++ b/YesNt.Interpreter/Runtime/StatementRuntimeInfo.cs
@@ -1,6 +1,16 @@
namespace YesNt.Interpreter.Runtime;
+///
+/// Base class for all classes that host statement handler methods.
+/// Subclasses declare methods decorated with or
+/// ; the source generator
+/// (GeneratedStatementRegistry) discovers these at compile time and wires them up.
+///
internal abstract class StatementRuntimeInformation
{
+ ///
+ /// Gets or sets the runtime state for the current execution context.
+ /// Injected by the generated registry before any handler is invoked.
+ ///
public RuntimeInformation RuntimeInfo { get; set; }
}
\ No newline at end of file
diff --git a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
index 02a3f65..462918a 100644
--- a/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
+++ b/YesNt.Interpreter/Runtime/YesNtInterpreter.cs
@@ -10,16 +10,45 @@ using YesNt.Interpreter.Utilities;
namespace YesNt.Interpreter.Runtime;
+///
+/// The main entry point for executing YesNt scripts.
+///
+///
+/// Running a script file:
+///
+/// var interpreter = new YesNtInterpreter();
+/// interpreter.Execute("path/to/script.ynt");
+///
+/// Running script lines in memory with a custom statement:
+///
+/// var interpreter = new YesNtInterpreter();
+/// interpreter.AddStatement("log", SearchMode.StartOfLine, SpaceAround.End, args =>
+/// Console.WriteLine($"[LOG] {args}"));
+/// interpreter.Execute(new List<string> { "log hello world" });
+///
+///
public class YesNtInterpreter
{
+ ///
+ /// Raised after each line is executed in debug mode. The argument is
+ /// when execution ends (either normally or due to an error), allowing callers to detect completion.
+ ///
public event Action OnLineExecuted;
+ ///
+ /// Raised in debug mode whenever the script produces output (e.g. via print_line).
+ /// In non-debug mode output is written directly to .
+ ///
public event Action OnDebugOutput;
private readonly RuntimeInformation runtimeInfo = new RuntimeInformation();
private Dictionary> statements;
private readonly List> staticStatements;
+ ///
+ /// Gets a read-only snapshot of all currently registered statements.
+ /// Useful for building syntax highlighters or documentation tools.
+ ///
public ReadOnlyCollection StatementInformation
{
get
@@ -41,6 +70,16 @@ public class YesNtInterpreter
}
}
+ ///
+ /// Registers a custom statement using a pre-built .
+ /// If a statement with the same attribute key already exists it will be replaced.
+ /// The statement list is re-sorted by priority after insertion.
+ ///
+ /// 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).
+ ///
public void AddStatement(StatementAttribute attribute, Action handler)
{
statements[attribute] = handler;
@@ -50,16 +89,34 @@ public class YesNtInterpreter
.ToDictionary(x => x.Key, x => x.Value);
}
+ ///
+ /// Registers a custom statement without a syntax-highlight colour.
+ ///
+ /// The keyword that identifies this statement in source code.
+ /// Where in the line the keyword is matched.
+ /// Which sides of the keyword require a surrounding space.
+ /// The delegate invoked when the statement matches.
public void AddStatement(string name, SearchMode searchMode, SpaceAround spaceAround, Action handler)
{
AddStatement(new StatementAttribute(name, searchMode, spaceAround), handler);
}
+ ///
+ /// Registers a custom statement with a syntax-highlight colour.
+ ///
+ /// The keyword that identifies this statement in source code.
+ /// Where in the line the keyword is matched.
+ /// Which sides of the keyword require a surrounding space.
+ /// The colour used for syntax highlighting in the code editor.
+ /// The delegate invoked when the statement matches.
public void AddStatement(string name, SearchMode searchMode, SpaceAround spaceAround, ConsoleColor consoleColor, Action handler)
{
AddStatement(new StatementAttribute(name, searchMode, spaceAround, consoleColor), handler);
}
+ ///
+ /// Initialises a new and registers all built-in statements.
+ ///
public YesNtInterpreter()
{
GeneratedStatementRegistry.Register(runtimeInfo, out statements, out staticStatements);
@@ -68,11 +125,23 @@ public class YesNtInterpreter
runtimeInfo.OnLineExecuted += e => OnLineExecuted?.Invoke(e);
}
+ ///
+ /// Requests a graceful stop of the currently executing script.
+ /// The interpreter will terminate at the next line boundary.
+ ///
public void Stop()
{
runtimeInfo.Exit(ExitMessages.TerminatedByExternalProcess, true);
}
+ ///
+ /// Executes a YesNt script file.
+ ///
+ /// The path to the .ynt script file.
+ ///
+ /// When , output is routed through instead of
+ /// and line-execution events are raised via .
+ ///
public void Execute(string path, bool isDebugMode = false)
{
runtimeInfo.Reset();
@@ -83,6 +152,14 @@ public class YesNtInterpreter
}
}
+ ///
+ /// Executes a YesNt script supplied as an in-memory list of lines.
+ ///
+ /// The script lines to execute.
+ ///
+ /// When , output is routed through and
+ /// line-execution events are raised via .
+ ///
public void Execute(List lines, bool isDebugMode = false)
{
runtimeInfo.Reset();
diff --git a/YesNt.Interpreter/Utilities/Evaluator.cs b/YesNt.Interpreter/Utilities/Evaluator.cs
index a13fa91..427731a 100644
--- a/YesNt.Interpreter/Utilities/Evaluator.cs
+++ b/YesNt.Interpreter/Utilities/Evaluator.cs
@@ -4,8 +4,19 @@ using System.Text.RegularExpressions;
namespace YesNt.Interpreter.Utilities;
+///
+/// Provides expression evaluation used by conditional and arithmetic statements.
+///
internal static partial class Evaluator
{
+ ///
+ /// Evaluates a boolean condition string such as a == b, x > 3, or true.
+ ///
+ /// The condition expression, which may contain safe-string encoded values.
+ ///
+ /// or if the condition could be evaluated;
+ /// if the expression is not a recognised condition form (treated as an error by callers).
+ ///
public static bool? EvaluateCondition(string input)
{
if (input.ToLower().FromSafeString().Trim() == "true")
@@ -68,6 +79,13 @@ internal static partial class Evaluator
return null;
}
+ ///
+ /// Evaluates a numeric arithmetic expression string and returns the result as a string.
+ /// Supports +, -, *, and / operators.
+ /// Adjacent sign characters (++, --, -+, +-) are normalised before evaluation.
+ ///
+ /// The arithmetic expression to evaluate.
+ /// The result as a culture-invariant numeric string, or "NaN" if evaluation failed.
public static string Calculate(string input)
{
input = PlusPlusRegex().Replace(input, "+");
diff --git a/YesNt.Interpreter/Utilities/FixedProcess.cs b/YesNt.Interpreter/Utilities/FixedProcess.cs
index 28b401a..9430c88 100644
--- a/YesNt.Interpreter/Utilities/FixedProcess.cs
+++ b/YesNt.Interpreter/Utilities/FixedProcess.cs
@@ -11,6 +11,14 @@ public delegate void DataReceivedEventHandler(object sender, DataReceivedEventAr
internal delegate void UserCallBack(string data);
+///
+/// A workaround replacement for that fixes a buffering
+/// issue in / :
+/// the BCL implementation only delivers data when a newline is encountered, which means partial
+/// lines are not raised until the process writes another newline or exits.
+/// flushes whatever is in the read buffer immediately, enabling real-time
+/// output forwarding for interactive child processes.
+///
public class FixedProcess : Process
{
public new event DataReceivedEventHandler OutputDataReceived;
diff --git a/YesNt.Interpreter/Utilities/StringExtentions.cs b/YesNt.Interpreter/Utilities/StringExtentions.cs
index a28f1ea..71d13f7 100644
--- a/YesNt.Interpreter/Utilities/StringExtentions.cs
+++ b/YesNt.Interpreter/Utilities/StringExtentions.cs
@@ -6,10 +6,27 @@ using System.Text;
namespace YesNt.Interpreter.Utilities;
+///
+/// Extension methods for string manipulation used throughout the interpreter.
+///
+///
+///
+/// YesNt uses a "safe string" encoding to pass values through the interpreter pipeline without
+/// accidentally triggering keyword matching. Special characters (spaces, operators, punctuation,
+/// control characters) are replaced with tilde-prefixed three-letter codes
+/// (e.g. space → ~spc, newline → ~nli). The mapping is defined in
+/// . Use to encode and
+/// to decode.
+///
+///
public static class StringExtensions
{
private static readonly Dictionary reverseReplacementRules;
+ ///
+ /// Gets the table that maps special characters to their safe-string escape codes.
+ /// Keys are the original characters; values are the three-letter tilde codes.
+ ///
public static Dictionary ReplacementRules { get; } = new()
{
{"~", "~til" },
@@ -34,6 +51,13 @@ public static class StringExtensions
reverseReplacementRules = ReplacementRules.ToDictionary(x => x.Value, x => x.Key);
}
+ ///
+ /// Encodes a string into safe-string format so that special characters cannot accidentally
+ /// trigger interpreter keyword matching. Each character is wrapped with vertical-tab sentinels
+ /// before rule substitution so that multi-character replacements do not overlap.
+ ///
+ /// The plain string to encode.
+ /// The safe-string encoded representation.
public static string ToSafeString(this string input)
{
StringBuilder output = new StringBuilder();
@@ -45,28 +69,53 @@ public static class StringExtensions
return ReplaceOnce(output.ToString(), ReplacementRules);
}
+ ///
+ /// Decodes a safe-string back to its original plain-text form.
+ ///
+ /// A safe-string encoded string.
+ /// The decoded plain string.
public static string FromSafeString(this string input)
{
return ReplaceOnce(input.Replace("\v", string.Empty), reverseReplacementRules);
}
+ ///
+ /// Tries to parse the string as a , first decoding safe-string encoding
+ /// and normalising decimal separators (comma → period).
+ ///
+ /// The string to parse (may be safe-string encoded).
+ /// When this method returns, contains the parsed value if successful.
+ /// if parsing succeeded; otherwise .
public static bool ToStandardizedNumber(this string input, out double result)
{
return double.TryParse(input.FromSafeString().Replace(',', '.'), NumberStyles.Any, CultureInfo.InvariantCulture, out result);
}
+ /// Replaces only the first occurrence of in the string.
+ /// The source string.
+ /// The substring to find.
+ /// The replacement value.
+ /// A new string with the first occurrence replaced.
public static string ReplaceFirstOccurrence(this string input, string oldValue, string newValue)
{
int place = input.IndexOf(oldValue);
return input.Remove(place, oldValue.Length).Insert(place, newValue);
}
+ /// Replaces only the last occurrence of in the string.
+ /// The source string.
+ /// The substring to find.
+ /// The replacement value.
+ /// A new string with the last occurrence replaced.
public static string ReplaceLastOccurrence(this string input, string oldValue, string newValue)
{
int place = input.LastIndexOf(oldValue);
return input.Remove(place, Math.Min(oldValue.Length, input.Length - place)).Insert(place, newValue);
}
+ /// Counts the number of trailing whitespace characters in the string.
+ /// The source string.
+ /// The number of whitespace characters at the end of the string.
public static int WhiteSpaceAtEnd(this string input)
{
int count = 0;
From 163bf677ae1575fe5f7ad499bdb30bd3b9b0bcb0 Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Wed, 4 Mar 2026 23:02:40 +0100
Subject: [PATCH 44/73] Add line formatting with auto indentation and fix
syntax highlighting in editor
---
YesNt.CodeEditor/Editor.cs | 112 ++++++++++++++++++++++++++
YesNt.CodeEditor/InputHandler.cs | 64 +++++++++------
YesNt.CodeEditor/SyntaxHighlighter.cs | 9 ++-
3 files changed, 158 insertions(+), 27 deletions(-)
diff --git a/YesNt.CodeEditor/Editor.cs b/YesNt.CodeEditor/Editor.cs
index 6bd5b21..6fead3e 100644
--- a/YesNt.CodeEditor/Editor.cs
+++ b/YesNt.CodeEditor/Editor.cs
@@ -203,6 +203,118 @@ internal class TextEditor
return padding;
}
+ public void FormatLines()
+ {
+ const int indentationSize = 4;
+ List blockStack = [];
+
+ for (int i = 0; i < Lines.Count; i++)
+ {
+ string trimmed = Lines[i].Trim(' ');
+ if (string.IsNullOrWhiteSpace(trimmed))
+ {
+ Lines[i] = string.Empty;
+ continue;
+ }
+
+ if (trimmed.StartsWith('#'))
+ {
+ Lines[i] = trimmed;
+ continue;
+ }
+
+ if (trimmed == "else:")
+ {
+ for (int j = blockStack.Count - 1; j >= 0; j--)
+ {
+ if (blockStack[j] is "if" or "else")
+ {
+ blockStack.RemoveAt(j);
+ break;
+ }
+ }
+ }
+ bool isTerminatingStatement = trimmed == "exit"
+ || trimmed.StartsWith("throw ", StringComparison.Ordinal)
+ || trimmed.StartsWith("error ", StringComparison.Ordinal);
+ bool closesFunctionBlock = isTerminatingStatement && blockStack.Count > 0 && blockStack[^1] == "func";
+
+ if (trimmed == "end_if")
+ {
+ for (int j = blockStack.Count - 1; j >= 0; j--)
+ {
+ if (blockStack[j] is "if" or "else")
+ {
+ blockStack.RemoveAt(j);
+ break;
+ }
+ }
+ }
+ else if (trimmed == "end_while")
+ {
+ for (int j = blockStack.Count - 1; j >= 0; j--)
+ {
+ if (blockStack[j] == "while")
+ {
+ blockStack.RemoveAt(j);
+ break;
+ }
+ }
+ }
+ else if (trimmed == "return")
+ {
+ for (int j = blockStack.Count - 1; j >= 0; j--)
+ {
+ if (blockStack[j] == "func")
+ {
+ blockStack.RemoveAt(j);
+ break;
+ }
+ }
+ }
+
+ int lineIndentation = closesFunctionBlock ? Math.Max(0, blockStack.Count - 1) : blockStack.Count;
+ Lines[i] = new string(' ', lineIndentation * indentationSize) + trimmed;
+
+ if (!isTerminatingStatement && (
+ (trimmed.StartsWith("if ", StringComparison.Ordinal) && trimmed.EndsWith(':'))
+ || (trimmed.StartsWith("while ", StringComparison.Ordinal) && trimmed.EndsWith(':'))
+ || (trimmed.StartsWith("func ", StringComparison.Ordinal) && trimmed.EndsWith(':'))
+ || trimmed == "else:"))
+ {
+ if (trimmed.StartsWith("if ", StringComparison.Ordinal))
+ {
+ blockStack.Add("if");
+ }
+ else if (trimmed.StartsWith("while ", StringComparison.Ordinal))
+ {
+ blockStack.Add("while");
+ }
+ else if (trimmed.StartsWith("func ", StringComparison.Ordinal))
+ {
+ blockStack.Add("func");
+ }
+ else
+ {
+ blockStack.Add("else");
+ }
+ }
+
+ if (isTerminatingStatement)
+ {
+ while (blockStack.Count > 0 && blockStack[^1] != "func")
+ {
+ blockStack.RemoveAt(blockStack.Count - 1);
+ }
+
+ if (closesFunctionBlock && blockStack.Count > 0 && blockStack[^1] == "func")
+ {
+ blockStack.RemoveAt(blockStack.Count - 1);
+ }
+ }
+ }
+ }
+
private static string ToLiteral(string input)
{
return Microsoft.CodeAnalysis.CSharp.SymbolDisplay.FormatLiteral(input, false);
diff --git a/YesNt.CodeEditor/InputHandler.cs b/YesNt.CodeEditor/InputHandler.cs
index bf24a9e..5eb365d 100644
--- a/YesNt.CodeEditor/InputHandler.cs
+++ b/YesNt.CodeEditor/InputHandler.cs
@@ -47,6 +47,12 @@ internal class InputHandler(TextEditor textEditor)
case ConsoleKey.E:
textEditor.CursorPosition.X = textEditor.Lines.Count > textEditor.CursorPosition.Y ? textEditor.Lines[textEditor.CursorPosition.Y].TrimEnd().Length : 0;
return true;
+
+ case ConsoleKey.F:
+ textEditor.FormatLines();
+ textEditor.Display(true);
+ WriteStatus("Formatted!");
+ return true;
}
}
if (keyInfo.Key == ConsoleKey.DownArrow)
@@ -274,6 +280,11 @@ internal class InputHandler(TextEditor textEditor)
WriteStatus(string.Empty);
break;
+ case "format":
+ textEditor.FormatLines();
+ WriteStatus("Formatted!");
+ break;
+
case "exit":
return false;
@@ -331,30 +342,37 @@ internal class InputHandler(TextEditor textEditor)
private void ExecuteWithDebugScreen(string saveInput, bool debugMode, bool stepMode)
{
- if (textEditor.Save(saveInput, true))
+ string[] parts = saveInput.Split(' ', StringSplitOptions.RemoveEmptyEntries);
+ bool hasPathArgument = parts.Length > 1;
+ bool canRunUnsavedBuffer = !hasPathArgument && string.IsNullOrWhiteSpace(textEditor.CurrentPath);
+
+ bool canExecute = canRunUnsavedBuffer || textEditor.Save(saveInput, true);
+ if (!canExecute)
{
- textEditor.EditMode = Mode.Debug;
- textEditor.IsStepDebugMode = stepMode;
- Console.Clear();
- Console.CursorVisible = true;
-
- if (debugMode)
- {
- textEditor.YesNtInterpreter.Execute(textEditor.CurrentPath, true);
- }
- else
- {
- textEditor.YesNtInterpreter.Execute(textEditor.CurrentPath);
- }
-
- while (Console.KeyAvailable)
- {
- _ = Console.ReadKey(true);
- }
- _ = Console.ReadKey();
- WriteStatus(string.Empty);
- textEditor.IsStepDebugMode = false;
- textEditor.EditMode = Mode.Command;
+ return;
}
+
+ textEditor.EditMode = Mode.Debug;
+ textEditor.IsStepDebugMode = stepMode;
+ Console.Clear();
+ Console.CursorVisible = true;
+
+ if (canRunUnsavedBuffer)
+ {
+ textEditor.YesNtInterpreter.Execute([.. textEditor.Lines], debugMode);
+ }
+ else
+ {
+ textEditor.YesNtInterpreter.Execute(textEditor.CurrentPath, debugMode);
+ }
+
+ while (Console.KeyAvailable)
+ {
+ _ = Console.ReadKey(true);
+ }
+ _ = Console.ReadKey();
+ WriteStatus(string.Empty);
+ textEditor.IsStepDebugMode = false;
+ textEditor.EditMode = Mode.Command;
}
}
diff --git a/YesNt.CodeEditor/SyntaxHighlighter.cs b/YesNt.CodeEditor/SyntaxHighlighter.cs
index 7b8daa1..8db25f7 100644
--- a/YesNt.CodeEditor/SyntaxHighlighter.cs
+++ b/YesNt.CodeEditor/SyntaxHighlighter.cs
@@ -30,7 +30,7 @@ internal partial class SyntaxHighlighter(ReadOnlyCollection statement.Name.Trim()
};
input = input.TrimEnd(' ');
- if (statement.SearchMode == SearchMode.StartOfLine && input.StartsWith(name))
+ string inputTrim = input.Trim(' ');
+ if (statement.SearchMode == SearchMode.StartOfLine && inputTrim.StartsWith(name))
{
if (statement.Separator is not null && input.Contains(statement.Separator))
{
@@ -78,7 +79,7 @@ internal partial class SyntaxHighlighter(ReadOnlyCollection
Date: Wed, 4 Mar 2026 23:33:08 +0100
Subject: [PATCH 45/73] Add proper docs
---
README.md | 16 +-
YesNt.CodeEditor/InputHandler.cs | 12 +-
YesNt.Interpreter/Utilities/Evaluator.cs | 3 +-
docs/README.md | 47 ++
docs/editor.md | 52 ++
docs/language-reference.md | 811 +++++++++++++++++++++++
docs/library-api.md | 265 ++++++++
7 files changed, 1198 insertions(+), 8 deletions(-)
create mode 100644 docs/README.md
create mode 100644 docs/editor.md
create mode 100644 docs/language-reference.md
create mode 100644 docs/library-api.md
diff --git a/README.md b/README.md
index bf67f69..59da794 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,17 @@
# YesNt
-
+
> YesNt is a imperative and interpreted language inspired by the Assembly language.
-## Syntax
+## Documentation
-Current language syntax is documented in [SYNTAX_V2.md](SYNTAX_V2.md).
+| Document | Description |
+| -------------------------------------------------------- | ----------------------------------------- |
+| [docs/README.md](docs/README.md) | Getting started |
+| [docs/language-reference.md](docs/language-reference.md) | Full language reference |
+| [docs/library-api.md](docs/library-api.md) | Embedding the interpreter as a C# library |
+| [docs/editor.md](docs/editor.md) | Using the terminal code editor |
-Example:
+## Quick example
```ynt
var name = world
@@ -16,6 +21,5 @@ print_line Hello ${name}
## Run
```bash
-dotnet run --project YesNt.Interpreter -- path/to/script.ynt
+dotnet run --project YesNt.Interpreter.App -- path/to/script.ynt
```
-
diff --git a/YesNt.CodeEditor/InputHandler.cs b/YesNt.CodeEditor/InputHandler.cs
index 5eb365d..b937493 100644
--- a/YesNt.CodeEditor/InputHandler.cs
+++ b/YesNt.CodeEditor/InputHandler.cs
@@ -48,6 +48,14 @@ internal class InputHandler(TextEditor textEditor)
textEditor.CursorPosition.X = textEditor.Lines.Count > textEditor.CursorPosition.Y ? textEditor.Lines[textEditor.CursorPosition.Y].TrimEnd().Length : 0;
return true;
+ case ConsoleKey.R:
+ ExecuteWithDebugScreen("run", false, false);
+ return true;
+
+ case ConsoleKey.D:
+ ExecuteWithDebugScreen("debug", true, false);
+ return true;
+
case ConsoleKey.F:
textEditor.FormatLines();
textEditor.Display(true);
@@ -352,6 +360,8 @@ internal class InputHandler(TextEditor textEditor)
return;
}
+ Mode previousMode = textEditor.EditMode;
+
textEditor.EditMode = Mode.Debug;
textEditor.IsStepDebugMode = stepMode;
Console.Clear();
@@ -373,6 +383,6 @@ internal class InputHandler(TextEditor textEditor)
_ = Console.ReadKey();
WriteStatus(string.Empty);
textEditor.IsStepDebugMode = false;
- textEditor.EditMode = Mode.Command;
+ textEditor.EditMode = previousMode;
}
}
diff --git a/YesNt.Interpreter/Utilities/Evaluator.cs b/YesNt.Interpreter/Utilities/Evaluator.cs
index 427731a..339e1b5 100644
--- a/YesNt.Interpreter/Utilities/Evaluator.cs
+++ b/YesNt.Interpreter/Utilities/Evaluator.cs
@@ -81,7 +81,8 @@ internal static partial class Evaluator
///
/// Evaluates a numeric arithmetic expression string and returns the result as a string.
- /// Supports +, -, *, and / operators.
+ /// Supports +, -, *, /, % (modulo), and ^ (power) operators
+ /// with standard precedence (^ highest, +/- lowest) and parentheses.
/// Adjacent sign characters (++, --, -+, +-) are normalised before evaluation.
///
/// The arithmetic expression to evaluate.
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..3076695
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,47 @@
+# YesNt Documentation
+
+YesNt is a line-based, interpreted scripting language inspired by assembly.
+Each line is one statement. There are no multi-line expressions.
+
+## Guides
+
+| Document | Description |
+| ------------------------------------------- | ---------------------------------------------------- |
+| [Language Reference](language-reference.md) | Every statement, token, and operator in the language |
+| [Library API](library-api.md) | How to embed the interpreter in a C# project |
+| [Editor](editor.md) | How to use the terminal code editor |
+
+## Quick start
+
+### Running a script from the command line
+
+```bash
+dotnet run --project YesNt.Interpreter.App -- path/to/script.ynt
+```
+
+### Hello world
+
+```ynt
+print_line Hello, world!
+```
+
+### Variables and output
+
+```ynt
+var name = Alice
+print_line Hello, ${name}!
+```
+
+### Functions
+
+```ynt
+func greet:
+ var msg = Hello, ${name}!
+ print_line ${msg}
+return
+
+var name = Bob
+call greet
+```
+
+Script files use the `.ynt` extension by convention.
diff --git a/docs/editor.md b/docs/editor.md
new file mode 100644
index 0000000..0253100
--- /dev/null
+++ b/docs/editor.md
@@ -0,0 +1,52 @@
+# YesNt Code Editor
+
+`YesNt.CodeEditor` is a terminal editor for writing, formatting, running, and debugging YesNt scripts.
+
+## Start the editor
+
+```bash
+dotnet run --project YesNt.CodeEditor -- [optional-path-to-file.ynt]
+```
+
+If you pass a file path, it is loaded on startup.
+
+## Modes
+
+- **Command mode:** enter editor commands in the `>>>` prompt.
+- **Edit mode:** direct text editing with keyboard navigation.
+- **Debug mode:** script output/debug information while running.
+
+## Command mode commands
+
+| Command | Description |
+| --------------------- | --------------------------------------------------------- |
+| `edit` | Switch to edit mode |
+| `line ` | Jump to line `n` and switch to edit mode |
+| `save [path]` | Save to current path or a new path |
+| `load ` | Load a file |
+| `new` | Create new file |
+| `format` | Auto-format indentation |
+| `run [path]` | Run script |
+| `debug [path] [step]` | Run in debug mode (`step` enables step-by-step execution) |
+| `exit` | Close the editor |
+
+## Edit mode controls
+
+- Arrow keys: move cursor
+- Enter: split line
+- Backspace/Delete: remove characters/merge lines
+- **Alt+C:** return to command mode
+- **Alt+T:** jump to top
+- **Alt+B:** jump to bottom
+- **Alt+S:** jump to start of line
+- **Alt+E:** jump to end of line
+- **Alt+R:** run script
+- **Alt+D:** run debug mode
+- **Alt+F:** format current file
+
+## Formatter behavior (quick summary)
+
+- Indents `func`, `if`, `else`, and `while` blocks.
+- Dedents on `return`, `end_if`, and `end_while`.
+- `exit` / `throw` / `error` close active non-function blocks for following lines.
+- Comment lines (`# ...`) are kept unindented.
diff --git a/docs/language-reference.md b/docs/language-reference.md
new file mode 100644
index 0000000..834e207
--- /dev/null
+++ b/docs/language-reference.md
@@ -0,0 +1,811 @@
+# YesNt Language Reference
+
+YesNt is a line-based scripting language. Every non-empty, non-comment line is one statement.
+Execution proceeds top-to-bottom unless a control-flow statement changes the line counter.
+
+---
+
+## Table of contents
+
+1. [Basic rules](#basic-rules)
+2. [Comments](#comments)
+3. [String literals](#string-literals)
+4. [Variables](#variables)
+5. [Console I/O](#console-io)
+6. [Arithmetic](#arithmetic)
+7. [Conditions](#conditions)
+8. [Control flow](#control-flow)
+9. [Functions](#functions)
+10. [Lists](#lists)
+11. [Processing](#processing)
+12. [System](#system)
+13. [Predefined tokens](#predefined-tokens)
+14. [Termination](#termination)
+
+---
+
+## Basic rules
+
+- Lines are trimmed of leading and trailing whitespace before execution.
+- Blank lines are silently skipped.
+- Lines starting with `#` are comments and are silently skipped.
+- Variable interpolation uses `${name}` and is evaluated before the statement runs.
+- Special characters inside string literals are encoded internally and decoded on output — this is transparent to scripts.
+
+---
+
+## Comments
+
+```ynt
+# This is a comment.
+print_line Hello # inline comments are NOT supported — everything after print_line is the argument
+```
+
+Only whole-line comments (lines whose first non-whitespace character is `#`) are supported.
+
+---
+
+## String literals
+
+Double-quoted strings protect their content from keyword matching and allow escape sequences.
+
+```ynt
+print_line "Hello, world!"
+print_line "Line one\nLine two"
+print_line "She said \"hi\""
+```
+
+| Escape | Meaning |
+| ------ | -------------------- |
+| `\n` | Newline |
+| `\r` | Carriage return |
+| `\t` | Horizontal tab |
+| `\"` | Literal double-quote |
+| `\\` | Literal backslash |
+
+Variable interpolation (`${name}`) is **not** evaluated inside string literals — the braces
+and content are passed through verbatim.
+
+```ynt
+var x = world
+print_line "${x}" # prints the literal text: ${x}
+print_line "hello " ${x} # prints: hello world (interpolation outside the literal)
+```
+
+---
+
+## Variables
+
+### Local variables — `var`
+
+```
+var =
+```
+
+Defines or updates a variable scoped to the current function (or the top level if called outside a function).
+The value is everything after `=`, trimmed.
+
+```ynt
+var count = 0
+var greeting = Hello, world!
+```
+
+Variable names may only contain letters and digits (`[a-zA-Z0-9]`).
+
+### Global variables — `global`
+
+```
+global =
+```
+
+Defines or updates a variable that is visible across all function scopes and background tasks.
+
+```ynt
+global total = 100
+```
+
+### Reading a variable — `${name}`
+
+`${name}` is an inline token that is replaced with the variable's value before the statement executes.
+It can appear anywhere in a line and multiple occurrences are replaced left to right.
+Local variables are checked first; if not found, the global table is checked.
+
+```ynt
+var a = 5
+var b = 10
+print_line ${a} plus ${b}
+```
+
+### Deleting a variable — `delete`
+
+```
+delete
+```
+
+Removes the variable. Local scope is checked first; if not found, the global table is used.
+Raises an error if the variable does not exist in either scope.
+
+```ynt
+var temp = scratch
+delete temp
+```
+
+---
+
+## Console I/O
+
+### Print with newline — `print_line`
+
+```
+print_line
+print_line
+```
+
+Writes `` followed by a newline. With no argument, writes a blank line.
+
+```ynt
+print_line Hello!
+print_line
+print_line Done.
+```
+
+### Print without newline — `print`
+
+```
+print
+```
+
+Writes `` without a trailing newline.
+
+```ynt
+print Enter your name:
+var name = %read_line
+print_line Hello, ${name}!
+```
+
+### Read a line of input — `%read_line`
+
+`%read_line` is an inline token that is replaced with one line of text read from standard input.
+
+```ynt
+var answer = %read_line
+print_line You typed: ${answer}
+```
+
+### Read a single key — `%read_key`
+
+`%read_key` is an inline token that is replaced with the single character pressed by the user (no Enter required).
+
+```ynt
+print Press any key...
+var key = %read_key
+print_line You pressed: ${key}
+```
+
+### Clear the console — `clear`
+
+```
+clear
+```
+
+Clears the console window.
+
+---
+
+## Arithmetic
+
+Arithmetic is a **postfix** modifier applied at the end of a line with the `calc` keyword.
+
+```
+ calc
+```
+
+Any numeric sub-expression matching the pattern `number op number [op number …]` is evaluated
+and replaced with the result. Supported operators (highest to lowest precedence):
+
+| Operator | Operation |
+| -------- | ----------------------------- |
+| `(…)` | Parentheses (evaluated first) |
+| `^` | Exponentiation |
+| `%` | Modulo |
+| `/` | Division |
+| `*` | Multiplication |
+| `-` | Subtraction |
+| `+` | Addition (lowest precedence) |
+
+Adjacent sign characters (`++`, `--`, `-+`, `+-`) are normalised before evaluation.
+
+```ynt
+var x = 3
+var y = 4
+var sum = ${x} + ${y} calc # 7
+var expr = 2 + 3 * 4 calc # 14 (* before +)
+var parens = (2 + 3) * 4 calc # 20
+var power = 2 ^ 10 calc # 1024
+var remainder = 17 % 5 calc # 2
+```
+
+---
+
+## Conditions
+
+Conditions are used in `if` and `while` statements. A condition is a string of the form:
+
+```
+
+```
+
+| Operator | Meaning |
+| -------- | --------------------------------------------- |
+| `==` | Equal (string comparison, case-sensitive) |
+| `!=` | Not equal (string comparison, case-sensitive) |
+| `<` | Less than (numeric) |
+| `>` | Greater than (numeric) |
+| `<=` | Less than or equal (numeric) |
+| `>=` | Greater than or equal (numeric) |
+
+Numeric comparisons (`<`, `>`, `<=`, `>=`) parse both sides with
+culture-invariant decimal rules (`.` or `,` as decimal separator).
+
+A bare value of `True` or `False` (case-insensitive) is also a valid condition.
+
+```ynt
+var x = 10
+if ${x} > 5:
+ print_line x is greater than 5
+end_if
+```
+
+---
+
+## Control flow
+
+### If / else / end_if
+
+```
+if :
+
+else:
+
+end_if
+```
+
+`else:` is optional. `if` / `else:` / `end_if` blocks can be nested.
+
+```ynt
+var score = 75
+if ${score} >= 60:
+ print_line Pass
+else:
+ print_line Fail
+end_if
+```
+
+### While loop
+
+```
+while :
+
+end_while
+```
+
+The condition is checked before each iteration. `while` / `end_while` blocks can be nested.
+
+```ynt
+var i = 1
+while ${i} <= 5:
+ print_line ${i}
+ var i = ${i} + 1 calc
+end_while
+```
+
+### Labels and goto
+
+```
+label :
+goto
+```
+
+`label` marks a target. `goto` performs an unconditional jump to that label.
+Labels are scoped to the current function; you cannot jump to a label outside the calling function.
+
+```ynt
+label loop:
+ print_line tick
+ goto loop
+```
+
+### Conditional goto
+
+```
+if goto