mirror of
https://github.com/Stone-Red-Code/YesNt-Interpreter.git
synced 2026-09-08 16:06:07 +02:00
- Add functions
- Code improvements
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
|
||||
using YesNt.Interpreter.Enums;
|
||||
|
||||
namespace YesNt.Interpreter.Attributes
|
||||
{
|
||||
[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 Seperator { get; set; }
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
using YesNt.Interpreter.Enums;
|
||||
|
||||
namespace YesNt.Interpreter.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||||
internal class StaticStatementAttribute : Attribute
|
||||
{
|
||||
public bool ExecuteInSearchLabelMode { get; set; }
|
||||
public Priority Priority { get; set; } = Priority.Normal;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace YesNt.Interpreter.Enums
|
||||
{
|
||||
internal enum Priority
|
||||
{
|
||||
Highest,
|
||||
VeryHigh,
|
||||
High,
|
||||
Normal,
|
||||
Low,
|
||||
VeryLow
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace YesNt.Interpreter.Enums
|
||||
{
|
||||
public enum SearchMode
|
||||
{
|
||||
StartOfLine,
|
||||
EndOfLine,
|
||||
Contains,
|
||||
Exact
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace YesNt.Interpreter.Enums
|
||||
{
|
||||
public enum SpaceAround
|
||||
{
|
||||
StartEnd,
|
||||
Start,
|
||||
End,
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace YesNt.Interpreter
|
||||
{
|
||||
internal 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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"profiles": {
|
||||
"YesNt-Interpreter": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "code.ynt"
|
||||
},
|
||||
"WSL": {
|
||||
"commandName": "WSL2",
|
||||
"environmentVariables": {},
|
||||
"distributionName": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace YesNt.Interpreter.Runtime
|
||||
{
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YesNt.Interpreter.Runtime
|
||||
{
|
||||
internal class FunctionScope
|
||||
{
|
||||
public int CallerLine { get; }
|
||||
public Dictionary<string, string> Variables { get; } = new();
|
||||
|
||||
public FunctionScope(int callerLine)
|
||||
{
|
||||
CallerLine = callerLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using YesNt.Interpreter.Runtime;
|
||||
using YesNt.Interpreter.Utilities;
|
||||
|
||||
namespace YesNt.Interpreter
|
||||
{
|
||||
internal class RuntimeInformation
|
||||
{
|
||||
private RuntimeInformation parentRuntimeInformation;
|
||||
private static int internalTaskId = 0;
|
||||
private int taskId = 0;
|
||||
private readonly Dictionary<string, string> topVariables = new();
|
||||
|
||||
public Dictionary<string, string> GloablVariables { get; set; } = new();
|
||||
public Dictionary<string, int> Labels { get; } = new();
|
||||
public Dictionary<string, int> Functions { get; } = new();
|
||||
public Stack<FunctionScope> FunctionCallStack { get; } = new();
|
||||
public List<string> 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 CurrentFilePath { get; set; } = string.Empty;
|
||||
public bool IsTask => ParentRuntimeInformation is not null;
|
||||
public int TaskId => IsTask ? taskId : 0;
|
||||
|
||||
public bool InternalIsInFunction { get; private set; } = false;
|
||||
|
||||
public bool IsInFunction
|
||||
{
|
||||
get => InternalIsInFunction || FunctionCallStack.Count > 0;
|
||||
set => InternalIsInFunction = value;
|
||||
}
|
||||
|
||||
public Dictionary<string, string> Variables
|
||||
{
|
||||
get
|
||||
{
|
||||
if (FunctionCallStack.Count == 0)
|
||||
{
|
||||
return topVariables;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FunctionCallStack.Peek().Variables;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RuntimeInformation ParentRuntimeInformation
|
||||
{
|
||||
get => parentRuntimeInformation;
|
||||
set
|
||||
{
|
||||
parentRuntimeInformation = value;
|
||||
if (parentRuntimeInformation is not null)
|
||||
{
|
||||
parentRuntimeInformation.OnExit += ParentRuntimeInformation_OnExit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSearching => !string.IsNullOrWhiteSpace(SearchLabel + SearchFunction) || IsInFunction && FunctionCallStack.Count == 0;
|
||||
|
||||
private event Action<string, bool> OnExit;
|
||||
|
||||
public event Action<string> OnDebugOutput;
|
||||
|
||||
public event Action<DebugEventArgs> OnLineExecuted;
|
||||
|
||||
private void ParentRuntimeInformation_OnExit(string exitMessage, bool stopChildTasks)
|
||||
{
|
||||
Exit($"Terminated by parent task", stopChildTasks);
|
||||
}
|
||||
|
||||
public void WriteLine(string output, bool forceWrite = false)
|
||||
{
|
||||
if (Stop && !forceWrite || parentRuntimeInformation?.StopAllTasks == true && !forceWrite)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsDebugMode)
|
||||
{
|
||||
if (IsTask)
|
||||
{
|
||||
parentRuntimeInformation.WriteLine(output.FromSaveString(), forceWrite);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnDebugOutput?.Invoke(output.FromSaveString() + Environment.NewLine);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(output.FromSaveString());
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(string output, bool forceWrite = false)
|
||||
{
|
||||
if (Stop && !forceWrite || parentRuntimeInformation?.StopAllTasks == true && !forceWrite)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsDebugMode)
|
||||
{
|
||||
if (IsTask)
|
||||
{
|
||||
parentRuntimeInformation.Write(output.FromSaveString(), forceWrite);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnDebugOutput?.Invoke(output.FromSaveString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write(output.FromSaveString());
|
||||
}
|
||||
}
|
||||
|
||||
public void Exit(string message, bool stopAllTasks)
|
||||
{
|
||||
if (!Stop)
|
||||
{
|
||||
WriteLine($"{Environment.NewLine}[{(IsTask ? $"Task: {TaskId}" : "The process")} was terminated at line {LineNumber + 1} with the message: {message}]", true);
|
||||
Stop = true;
|
||||
}
|
||||
if (stopAllTasks == true && StopAllTasks == false)
|
||||
{
|
||||
StopAllTasks = true;
|
||||
OnExit?.Invoke(message, StopAllTasks);
|
||||
parentRuntimeInformation?.Exit("Terminated by child task", true);
|
||||
}
|
||||
}
|
||||
|
||||
public void LineExecuted(DebugEventArgs debugEventArgs)
|
||||
{
|
||||
if (IsTask)
|
||||
{
|
||||
parentRuntimeInformation.LineExecuted(debugEventArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnLineExecuted?.Invoke(debugEventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
topVariables.Clear();
|
||||
Lines.Clear();
|
||||
GloablVariables.Clear();
|
||||
Labels.Clear();
|
||||
Functions.Clear();
|
||||
FunctionCallStack.Clear();
|
||||
ParentRuntimeInformation = null;
|
||||
SearchLabel = string.Empty;
|
||||
SearchFunction = string.Empty;
|
||||
CurrentFilePath = string.Empty;
|
||||
CurrentLine = string.Empty;
|
||||
Stop = false;
|
||||
StopAllTasks = false;
|
||||
IsDebugMode = false;
|
||||
IsInFunction = false;
|
||||
InternalIsInFunction = false;
|
||||
LineNumber = 0;
|
||||
taskId = internalTaskId + 1;
|
||||
internalTaskId++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
using YesNt.Interpreter.Enums;
|
||||
|
||||
namespace YesNt.Interpreter.Runtime
|
||||
{
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace YesNt.Interpreter
|
||||
{
|
||||
internal abstract class StatementRuntimeInformation
|
||||
{
|
||||
public RuntimeInformation RuntimeInfo { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
using System;
|
||||
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;
|
||||
using YesNt.Interpreter.Runtime;
|
||||
using YesNt.Interpreter.Utilities;
|
||||
|
||||
namespace YesNt.Interpreter
|
||||
{
|
||||
public class YesNtInterpreter
|
||||
{
|
||||
private readonly RuntimeInformation runtimeInfo = new RuntimeInformation();
|
||||
private Dictionary<StatementAttribute, Action<string>> statements = new();
|
||||
private List<KeyValuePair<StaticStatementAttribute, Action>> staticStatements = new();
|
||||
|
||||
public ReadOnlyCollection<StatementInformation> StatementInformation
|
||||
{
|
||||
get
|
||||
{
|
||||
List<StatementInformation> informations = statements.Select(s =>
|
||||
{
|
||||
return new StatementInformation()
|
||||
{
|
||||
Name = s.Key.Name,
|
||||
SearchMode = s.Key.SearchMode,
|
||||
SpaceAround = s.Key.SpaceAround,
|
||||
Color = s.Key.Color,
|
||||
IgnoreSyntaxHighlighting = s.Key.IgnoreSyntaxHighlighting,
|
||||
Seperator = s.Key.Seperator
|
||||
};
|
||||
}).ToList();
|
||||
|
||||
return new ReadOnlyCollection<StatementInformation>(informations);
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<DebugEventArgs> OnLineExecuted;
|
||||
|
||||
public event Action<string> OnDebugOutput;
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
runtimeInfo.Exit("Terminated by external process", true);
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
Type[] types = assembly.GetTypes();
|
||||
|
||||
IEnumerable<Type> statementRuntimeInfos = types.Where(t => t.IsSubclassOf(typeof(StatementRuntimeInformation)));
|
||||
|
||||
statements.Clear();
|
||||
|
||||
foreach (Type type in statementRuntimeInfos)
|
||||
{
|
||||
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<StatementAttribute>();
|
||||
if (statementAttribute is not null)
|
||||
{
|
||||
Action<string> method = methodInfo.CreateDelegate(typeof(Action<string>), statementInfo) as Action<string>;
|
||||
statements.Add(statementAttribute, method);
|
||||
}
|
||||
|
||||
StaticStatementAttribute staticStatementAttribute = methodInfo.GetCustomAttribute<StaticStatementAttribute>();
|
||||
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)
|
||||
{
|
||||
runtimeInfo.Reset();
|
||||
runtimeInfo.IsDebugMode = isDebugMode;
|
||||
LoadFile(path);
|
||||
Execute();
|
||||
}
|
||||
|
||||
internal void Execute(List<string> lines, Dictionary<string, string> 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)
|
||||
{
|
||||
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].TrimEnd().Replace("\r", string.Empty);
|
||||
|
||||
DebugEventArgs debugEventArgs = new DebugEventArgs()
|
||||
{
|
||||
LineNumber = runtimeInfo.LineNumber + 1,
|
||||
OriginalLine = runtimeInfo.CurrentLine.FromSaveString(),
|
||||
IsTask = runtimeInfo.IsTask,
|
||||
TaskId = runtimeInfo.TaskId
|
||||
};
|
||||
|
||||
if (string.IsNullOrWhiteSpace(runtimeInfo.CurrentLine))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<StaticStatementAttribute, Action> staticStatement in staticStatements)
|
||||
{
|
||||
StaticStatementAttribute staticStatementAttribute = staticStatement.Key;
|
||||
if (staticStatementAttribute.ExecuteInSearchLabelMode == false && runtimeInfo.IsSearching)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
staticStatement.Value.Invoke();
|
||||
}
|
||||
|
||||
bool statementFound = false;
|
||||
bool notSearchingLabel = !runtimeInfo.IsSearching;
|
||||
|
||||
foreach (KeyValuePair<StatementAttribute, Action<string>> statement in statements)
|
||||
{
|
||||
StatementAttribute statementAttribute = statement.Key;
|
||||
|
||||
if (statementAttribute.ExecuteInSearchMode == false && runtimeInfo.IsSearching)
|
||||
{
|
||||
statementFound = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (runtimeInfo.Stop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
string name = statementAttribute.SpaceAround switch
|
||||
{
|
||||
SpaceAround.StartEnd => $" {statementAttribute.Name.Trim()} ",
|
||||
SpaceAround.Start => $" {statementAttribute.Name.Trim()}",
|
||||
SpaceAround.End => $"{statementAttribute.Name.Trim()} ",
|
||||
_ => statementAttribute.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;
|
||||
|
||||
if (!leadingWhitespace)
|
||||
{
|
||||
runtimeInfo.CurrentLine = runtimeInfo.CurrentLine.Trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
runtimeInfo.CurrentLine = 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!statementFound)
|
||||
{
|
||||
runtimeInfo.Exit("Invalid statement", true);
|
||||
}
|
||||
if (runtimeInfo.IsDebugMode && notSearchingLabel)
|
||||
{
|
||||
debugEventArgs.CurrentLine = runtimeInfo.CurrentLine.FromSaveString();
|
||||
runtimeInfo.LineExecuted(debugEventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
if (runtimeInfo.Stop == false)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(runtimeInfo.SearchLabel))
|
||||
{
|
||||
runtimeInfo.Exit($"Label \"{runtimeInfo.SearchLabel}\" not found", true);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(runtimeInfo.SearchFunction))
|
||||
{
|
||||
runtimeInfo.Exit($"Function \"{runtimeInfo.SearchLabel}\" not found", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
runtimeInfo.Exit("End of file", false);
|
||||
}
|
||||
|
||||
if (runtimeInfo.IsDebugMode)
|
||||
{
|
||||
runtimeInfo.LineExecuted(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadFile(string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
runtimeInfo.Exit($"File \"{path}\" not found!", true);
|
||||
return;
|
||||
}
|
||||
|
||||
IEnumerable<string> lines = File.ReadAllLines(path);
|
||||
runtimeInfo.Lines.AddRange(lines);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
using System;
|
||||
|
||||
using YesNt.Interpreter.Attributes;
|
||||
using YesNt.Interpreter.Enums;
|
||||
using YesNt.Interpreter.Runtime;
|
||||
using YesNt.Interpreter.Utilities;
|
||||
|
||||
namespace YesNt.Interpreter.Statements
|
||||
{
|
||||
internal class CodeFlowStatements : StatementRuntimeInformation
|
||||
{
|
||||
[Statement("jmp", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow)]
|
||||
public void Jump(string args)
|
||||
{
|
||||
string key = args.Trim();
|
||||
|
||||
if (RuntimeInfo.Labels.ContainsKey(key))
|
||||
{
|
||||
RuntimeInfo.LineNumber = RuntimeInfo.Labels[key];
|
||||
}
|
||||
else
|
||||
{
|
||||
RuntimeInfo.SearchLabel = key;
|
||||
}
|
||||
}
|
||||
|
||||
[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));
|
||||
|
||||
if (RuntimeInfo.Functions.ContainsKey(key))
|
||||
{
|
||||
RuntimeInfo.LineNumber = RuntimeInfo.Functions[key];
|
||||
}
|
||||
else
|
||||
{
|
||||
RuntimeInfo.SearchFunction = key;
|
||||
}
|
||||
}
|
||||
|
||||
[Statement("jif", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow, Seperator = "|")]
|
||||
public void JumpIf(string args)
|
||||
{
|
||||
string[] parts = args.Split('|');
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
RuntimeInfo.Exit("Invalid syntax", true);
|
||||
return;
|
||||
}
|
||||
|
||||
string key = parts[0].Trim();
|
||||
string condition = parts[1].Trim();
|
||||
|
||||
bool? result = Evaluator.EvaluateCondition(condition);
|
||||
|
||||
if (result != true)
|
||||
{
|
||||
if (result is null)
|
||||
{
|
||||
RuntimeInfo.Exit("Invalid operation", true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (RuntimeInfo.Labels.ContainsKey(key))
|
||||
{
|
||||
RuntimeInfo.LineNumber = RuntimeInfo.Labels[key];
|
||||
}
|
||||
else
|
||||
{
|
||||
RuntimeInfo.SearchLabel = 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 != true)
|
||||
{
|
||||
if (result is null)
|
||||
{
|
||||
RuntimeInfo.Exit("Invalid operation", true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
RuntimeInfo.FunctionCallStack.Push(new FunctionScope(RuntimeInfo.LineNumber));
|
||||
|
||||
if (RuntimeInfo.Functions.ContainsKey(key))
|
||||
{
|
||||
RuntimeInfo.LineNumber = RuntimeInfo.Functions[key];
|
||||
}
|
||||
else
|
||||
{
|
||||
RuntimeInfo.SearchFunction = key;
|
||||
}
|
||||
}
|
||||
|
||||
[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;
|
||||
}
|
||||
}
|
||||
|
||||
[Statement("fnc", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
|
||||
public void FindFunction(string args)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
[Statement("ret", SearchMode.Exact, SpaceAround.None, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
|
||||
public void Return(string _)
|
||||
{
|
||||
if (!RuntimeInfo.IsInFunction)
|
||||
{
|
||||
RuntimeInfo.Exit("Not in function", true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (RuntimeInfo.IsSearching)
|
||||
{
|
||||
RuntimeInfo.IsInFunction = false;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
RuntimeInfo.IsInFunction = false;
|
||||
}
|
||||
|
||||
if (RuntimeInfo.FunctionCallStack.Count > 0)
|
||||
{
|
||||
RuntimeInfo.LineNumber = RuntimeInfo.FunctionCallStack.Pop().CallerLine;
|
||||
}
|
||||
else
|
||||
{
|
||||
RuntimeInfo.Exit("No function in stack", true);
|
||||
}
|
||||
}
|
||||
|
||||
[Statement("end", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red, ExecuteInSearchMode = true)]
|
||||
public void End(string _)
|
||||
{
|
||||
if (RuntimeInfo.IsSearching)
|
||||
{
|
||||
RuntimeInfo.IsInFunction = false;
|
||||
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;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
RuntimeInfo.IsInFunction = false;
|
||||
}
|
||||
|
||||
RuntimeInfo.Exit("Planned termination by code. Canceling all tasks", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
|
||||
using YesNt.Interpreter.Attributes;
|
||||
using YesNt.Interpreter.Enums;
|
||||
using YesNt.Interpreter.Utilities;
|
||||
|
||||
namespace YesNt.Interpreter.Statements
|
||||
{
|
||||
internal class ConsoleStatements : StatementRuntimeInformation
|
||||
{
|
||||
[Statement("cwl", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkGreen, Priority = Priority.VeryLow)]
|
||||
public void WriteLine(string args)
|
||||
{
|
||||
RuntimeInfo.WriteLine(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 "))
|
||||
{
|
||||
string input = Console.ReadLine();
|
||||
if (input is null)
|
||||
{
|
||||
RuntimeInfo.Exit("Terminated by external process", true);
|
||||
return;
|
||||
}
|
||||
args = args.ReplaceFirstOccurrence("%crl ", input.ToSaveString() + " ");
|
||||
}
|
||||
RuntimeInfo.CurrentLine = args.TrimEnd();
|
||||
}
|
||||
|
||||
[Statement("%cr", SearchMode.Contains, SpaceAround.End, ConsoleColor.DarkGreen, KeepStatementInArgs = true, Priority = Priority.Highest)]
|
||||
public void ReadKey(string args)
|
||||
{
|
||||
args += " ";
|
||||
while (args.Contains("%cr "))
|
||||
{
|
||||
string input = ConsoleExtentions.ReadKey(RuntimeInfo).ToString();
|
||||
args = args.ReplaceFirstOccurrence("%cr ", input.ToSaveString() + " ");
|
||||
}
|
||||
RuntimeInfo.CurrentLine = args.TrimEnd();
|
||||
}
|
||||
|
||||
[Statement("cls", SearchMode.Exact, SpaceAround.None, ConsoleColor.Magenta)]
|
||||
public void Clear(string args)
|
||||
{
|
||||
Console.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using YesNt.Interpreter.Attributes;
|
||||
using YesNt.Interpreter.Enums;
|
||||
using YesNt.Interpreter.Utilities;
|
||||
|
||||
namespace YesNt.Interpreter.Statements
|
||||
{
|
||||
internal class ProcessingStatements : StatementRuntimeInformation
|
||||
{
|
||||
[Statement("!calc", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.High, ExecuteInSearchMode = true)]
|
||||
public void Calculate(string args)
|
||||
{
|
||||
MatchCollection matches = Regex.Matches(args, @"((\)?)+(\(?)+[0-9]+(((\s?)+(\)?)(\s?)+\+(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\-(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\*(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\/(\s?)+(\(?)+(\s?)+)|[,.])(?=[0-9])+)+[0-9]+(\)?)+");
|
||||
|
||||
for (int i = 0; i < matches.Count; i++)
|
||||
{
|
||||
string res = Evaluator.Calculate(matches[i].Value);
|
||||
if (res is null)
|
||||
{
|
||||
RuntimeInfo.Exit("Invalid operation", true);
|
||||
return;
|
||||
}
|
||||
args = args.Replace(matches[0].Value, res);
|
||||
}
|
||||
|
||||
RuntimeInfo.CurrentLine = args;
|
||||
}
|
||||
|
||||
[Statement("!eval", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.VeryHigh)]
|
||||
public void Evaluate(string args)
|
||||
{
|
||||
RuntimeInfo.CurrentLine = args.FromSaveString();
|
||||
}
|
||||
|
||||
[Statement("!task", SearchMode.EndOfLine, SpaceAround.Start, ConsoleColor.DarkYellow, Priority = Priority.VeryHigh)]
|
||||
public void RunTask(string line)
|
||||
{
|
||||
int lineNumer = RuntimeInfo.LineNumber;
|
||||
List<string> lines = RuntimeInfo.Lines.GetRange(0, RuntimeInfo.Lines.Count);
|
||||
lines[lineNumer] = line;
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
YesNtInterpreter interpreter = new YesNtInterpreter();
|
||||
interpreter.Initialize();
|
||||
interpreter.Execute(lines, 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)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Path.GetExtension(path)))
|
||||
{
|
||||
path = Path.ChangeExtension(path, "ynt");
|
||||
}
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
try
|
||||
{
|
||||
RuntimeInfo.Lines.RemoveAt(0);
|
||||
RuntimeInfo.Lines.InsertRange(RuntimeInfo.LineNumber, File.ReadAllLines(path));
|
||||
RuntimeInfo.LineNumber--;
|
||||
}
|
||||
catch
|
||||
{
|
||||
RuntimeInfo.Exit($"Could not load file {path}", true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RuntimeInfo.Exit($"Could not find file {path}", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using YesNt.Interpreter.Attributes;
|
||||
using YesNt.Interpreter.Enums;
|
||||
|
||||
namespace YesNt.Interpreter.Statements
|
||||
{
|
||||
internal class VariableStatements : StatementRuntimeInformation
|
||||
{
|
||||
[Statement("<", SearchMode.StartOfLine, SpaceAround.None, Priority = Priority.VeryLow)]
|
||||
public void DefineVariable(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.Variables.ContainsKey(key))
|
||||
{
|
||||
RuntimeInfo.Variables[key] = parts[1].Trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
RuntimeInfo.Variables.Add(key, parts[1].Trim());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RuntimeInfo.Exit("Invalid syntax", true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[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);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
}
|
||||
|
||||
[StaticStatement(ExecuteInSearchLabelMode = true)]
|
||||
public void ReadVariable()
|
||||
{
|
||||
if (!RuntimeInfo.CurrentLine.Contains('>'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, string> variable in RuntimeInfo.Variables)
|
||||
{
|
||||
RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{variable.Key}", variable.Value);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, string> variable in RuntimeInfo.GloablVariables)
|
||||
{
|
||||
RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{variable.Key}", variable.Value);
|
||||
}
|
||||
|
||||
if (RuntimeInfo.IsSearching)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MatchCollection matches = Regex.Matches(RuntimeInfo.CurrentLine, @">[a-zA-Z0-9]+");
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace YesNt.Interpreter.Utilities
|
||||
{
|
||||
internal static class ConsoleExtentions
|
||||
{
|
||||
public static char ReadKey(RuntimeInformation runtimeInformation)
|
||||
{
|
||||
while (!runtimeInformation.Stop)
|
||||
{
|
||||
if (Console.KeyAvailable)
|
||||
{
|
||||
return Console.ReadKey().KeyChar;
|
||||
}
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
return ' ';
|
||||
}
|
||||
|
||||
public static void Sleep(int millisecondsTimeout, RuntimeInformation runtimeInformation)
|
||||
{
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
while (!runtimeInformation.Stop)
|
||||
{
|
||||
if (stopwatch.ElapsedMilliseconds > millisecondsTimeout)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace YesNt.Interpreter.Utilities
|
||||
{
|
||||
internal static class Evaluator
|
||||
{
|
||||
public static bool? EvaluateCondition(string input)
|
||||
{
|
||||
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)
|
||||
{
|
||||
bool succ1 = parts[0].ToStandardizedNumber(out double part1);
|
||||
bool succ2 = parts[1].ToStandardizedNumber(out double part2);
|
||||
if (!succ1 || !succ2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!succ1 || !succ2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!succ1 || !succ2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!succ1 || !succ2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return part1 <= part2;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string Calculate(string input, char op = '+')
|
||||
{
|
||||
if (input is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
MatchCollection matches = Regex.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 = Regex.Matches(input, @"\(([^()]+)\)");
|
||||
}
|
||||
|
||||
string[] parts = input.Split(op);
|
||||
|
||||
double number = double.NaN;
|
||||
|
||||
foreach (string p in parts)
|
||||
{
|
||||
string part = p;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
part = Calculate(part, '-');
|
||||
break;
|
||||
|
||||
case '-':
|
||||
part = Calculate(part, '*');
|
||||
break;
|
||||
|
||||
case '*':
|
||||
part = Calculate(part, '/');
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return number.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace YesNt.Interpreter.Utilities
|
||||
{
|
||||
public static class StringExtentions
|
||||
{
|
||||
public static string ToSaveString(this string input)
|
||||
{
|
||||
StringBuilder output = new StringBuilder();
|
||||
foreach (char c in input)
|
||||
{
|
||||
output.Append($"\r{c}\r");
|
||||
}
|
||||
return output.ToString();
|
||||
}
|
||||
|
||||
public static string FromSaveString(this string input)
|
||||
{
|
||||
return input.Replace("\r", "");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<RootNamespace>YesNt.Interpreter</RootNamespace>
|
||||
<ApplicationIcon />
|
||||
<OutputType>Exe</OutputType>
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,357 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace YesNt.Interpreter
|
||||
{
|
||||
public class YesNtInterpreter_OLD
|
||||
{
|
||||
private readonly Dictionary<string, string> variables = new Dictionary<string, string>();
|
||||
private readonly Dictionary<string, int> labels = new Dictionary<string, int>();
|
||||
private List<string> lines = new List<string>();
|
||||
private Stack<int> lastLabels = new();
|
||||
|
||||
public void Execute(string path)
|
||||
{
|
||||
lines.Clear();
|
||||
variables.Clear();
|
||||
labels.Clear();
|
||||
lastLabels.Clear();
|
||||
|
||||
LoadFile(path);
|
||||
|
||||
string searchLabel = string.Empty;
|
||||
|
||||
for (int lineNum = 0; lineNum < lines.Count; lineNum++)
|
||||
{
|
||||
string line = lines[lineNum].Trim().Replace("\r", "");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (searchLabel == string.Empty)
|
||||
{
|
||||
if (line.Contains("%crl"))
|
||||
{
|
||||
line = line.Replace("%crl", ToSaveString(Console.ReadLine()));
|
||||
}
|
||||
if (line.Contains("%cr"))
|
||||
{
|
||||
line = line.Replace("%cr", ToSaveString(Console.ReadKey().KeyChar.ToString()));
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, string> variable in variables)
|
||||
{
|
||||
line = line.Replace($">{variable.Key}", variable.Value);
|
||||
}
|
||||
|
||||
if (line.Contains(" "))
|
||||
{
|
||||
int index = line.IndexOf(' ');
|
||||
if (line.Contains(" = ") && line.IndexOf('=') > index)
|
||||
{
|
||||
index = line.IndexOf('=') + 1;
|
||||
}
|
||||
|
||||
string cmd = line.Substring(0, index);
|
||||
cmd += Calculate(line.Substring(index));
|
||||
line = cmd;
|
||||
}
|
||||
}
|
||||
|
||||
if (line.StartsWith("%lbl "))
|
||||
{
|
||||
string key = line.Substring(5).Trim();
|
||||
if (labels.ContainsKey(key))
|
||||
{
|
||||
labels[key] = lineNum;
|
||||
}
|
||||
else
|
||||
{
|
||||
labels.Add(key, lineNum);
|
||||
}
|
||||
|
||||
if (searchLabel != string.Empty && searchLabel == key)
|
||||
{
|
||||
searchLabel = string.Empty;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (searchLabel != string.Empty)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.StartsWith("%imp "))
|
||||
{
|
||||
string pat = line.Substring(5).Trim();
|
||||
lines.RemoveAt(lineNum);
|
||||
LoadFile(pat, lineNum);
|
||||
lineNum--;
|
||||
}
|
||||
else if (line.StartsWith("%jmp "))
|
||||
{
|
||||
string key = FromSaveString(line.Substring(5).Trim());
|
||||
lastLabels.Push(lineNum);
|
||||
|
||||
if (labels.ContainsKey(key))
|
||||
{
|
||||
lineNum = labels[key];
|
||||
}
|
||||
else
|
||||
{
|
||||
searchLabel = key;
|
||||
}
|
||||
}
|
||||
else if (line.StartsWith("%jif "))
|
||||
{
|
||||
if (line.Contains("|"))
|
||||
{
|
||||
string dat = line.Substring(5).Trim();
|
||||
string key = dat.Substring(0, dat.IndexOf('|')).Trim();
|
||||
string condition = dat.Substring(dat.IndexOf('|')).Replace("|", "").Trim();
|
||||
if (EvaluateCondition(condition))
|
||||
{
|
||||
lastLabels.Push(lineNum);
|
||||
if (labels.ContainsKey(key))
|
||||
{
|
||||
lineNum = labels[key];
|
||||
}
|
||||
else
|
||||
{
|
||||
searchLabel = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (line.Equals("%ret"))
|
||||
{
|
||||
lineNum = lastLabels.Pop();
|
||||
}
|
||||
else if (line.Equals("%end"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (line.StartsWith("%cwl "))
|
||||
{
|
||||
Console.WriteLine(FromSaveString(line.Substring(5)));
|
||||
}
|
||||
else if (line.StartsWith("%cw "))
|
||||
{
|
||||
Console.Write(FromSaveString(line.Substring(4)));
|
||||
}
|
||||
else if (line.StartsWith("<"))
|
||||
{
|
||||
string[] parts = line.Split(" = ");
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
string key = parts[0].Replace("<", "");
|
||||
if (variables.ContainsKey(key))
|
||||
{
|
||||
variables[key] = parts[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
variables.Add(key, parts[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadFile(string path, int index = 0)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
Console.WriteLine($"File \"{path}\" not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
string input = File.ReadAllText(path);
|
||||
string[] newLines = input.Split("\n");
|
||||
foreach (string line in newLines)
|
||||
{
|
||||
lines.Insert(index, line);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
private string ToSaveString(string input)
|
||||
{
|
||||
string output = "";
|
||||
foreach (char c in input)
|
||||
{
|
||||
output += $"\r{c}\r";
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
private string FromSaveString(string input)
|
||||
{
|
||||
return input.Replace("\r", "");
|
||||
}
|
||||
|
||||
private bool EvaluateCondition(string input)
|
||||
{
|
||||
string[] parts = input.Split(" == ");
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
string part1 = FromSaveString(parts[0]);
|
||||
string part2 = FromSaveString(parts[1]);
|
||||
return part1 == part2;
|
||||
}
|
||||
|
||||
parts = input.Split(" != ");
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
string part1 = FromSaveString(parts[0]);
|
||||
string part2 = FromSaveString(parts[1]);
|
||||
return part1 != part2;
|
||||
}
|
||||
|
||||
parts = input.Split(" > ");
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
bool succ1 = double.TryParse(FromSaveString(parts[0]), out double part1);
|
||||
bool succ2 = double.TryParse(FromSaveString(parts[1]), out double part2);
|
||||
if (!succ1 || !succ2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return part1 > part2;
|
||||
}
|
||||
|
||||
parts = input.Split(" < ");
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
bool succ1 = double.TryParse(FromSaveString(parts[0]), out double part1);
|
||||
bool succ2 = double.TryParse(FromSaveString(parts[1]), out double part2);
|
||||
if (!succ1 || !succ2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return part1 < part2;
|
||||
}
|
||||
|
||||
parts = input.Split(" >= ");
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
bool succ1 = double.TryParse(FromSaveString(parts[0]), out double part1);
|
||||
bool succ2 = double.TryParse(FromSaveString(parts[1]), out double part2);
|
||||
if (!succ1 || !succ2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return part1 >= part2;
|
||||
}
|
||||
|
||||
parts = input.Split(" <= ");
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
bool succ1 = double.TryParse(FromSaveString(parts[0]), out double part1);
|
||||
bool succ2 = double.TryParse(FromSaveString(parts[1]), out double part2);
|
||||
if (!succ1 || !succ2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return part1 <= part2;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string Calculate(string input, char op = '+')
|
||||
{
|
||||
string[] parts = input.Split($" {op} ");
|
||||
string result = "";
|
||||
|
||||
double number = double.NaN;
|
||||
int spacesToAdd = 0;
|
||||
|
||||
foreach (string p in parts)
|
||||
{
|
||||
string part = p;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
part = Calculate(part, '-');
|
||||
break;
|
||||
|
||||
case '-':
|
||||
part = Calculate(part, '*');
|
||||
break;
|
||||
|
||||
case '*':
|
||||
part = Calculate(part, '/');
|
||||
break;
|
||||
}
|
||||
if (double.TryParse(FromSaveString(part), out double num))
|
||||
{
|
||||
if (double.IsNaN(number))
|
||||
{
|
||||
spacesToAdd = CountSpaces(part);
|
||||
number = num;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
number += num;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
number -= num;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
number *= num;
|
||||
break;
|
||||
|
||||
case '/':
|
||||
number /= num;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!double.IsNaN(number))
|
||||
{
|
||||
result += new string(' ', spacesToAdd) + number;
|
||||
}
|
||||
|
||||
result += part;
|
||||
|
||||
number = double.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
if (!double.IsNaN(number))
|
||||
{
|
||||
result += new string(' ', spacesToAdd) + number;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int CountSpaces(string input)
|
||||
{
|
||||
int count = 0;
|
||||
while (input[count] == ' ')
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user