Initial commit

This commit is contained in:
Stone-Red-Code
2021-10-08 12:48:48 +02:00
commit c40d1f45e0
25 changed files with 2124 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
+334
View File
@@ -0,0 +1,334 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
+2
View File
@@ -0,0 +1,2 @@
# YesNt
+31
View File
@@ -0,0 +1,31 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31410.357
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YesNt.Interpreter", "YesNt-Interpreter\YesNt.Interpreter.csproj", "{1D79AC8F-9FC7-4B4C-9899-8DAF2B630030}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YesNt.CodeEditor", "YesNt.CodeEditor\YesNt.CodeEditor.csproj", "{33BDA036-A37E-475E-AACF-8ED96E31BA1A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1D79AC8F-9FC7-4B4C-9899-8DAF2B630030}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D79AC8F-9FC7-4B4C-9899-8DAF2B630030}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D79AC8F-9FC7-4B4C-9899-8DAF2B630030}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D79AC8F-9FC7-4B4C-9899-8DAF2B630030}.Release|Any CPU.Build.0 = Release|Any CPU
{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}.Release|Any CPU.ActiveCfg = Release|Any CPU
{33BDA036-A37E-475E-AACF-8ED96E31BA1A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8597E655-80C0-48F2-AEB1-4A279F5173D6}
EndGlobalSection
EndGlobal
@@ -0,0 +1,25 @@
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 Priority Priority { get; set; } = Priority.Normal;
public bool ExecuteInSearchLabelMode { get; set; }
public bool KeepStatementInArgs { get; set; }
public bool IgnoreSyntaxHighlighting { get; set; }
internal StatementAttribute(string name, SearchMode searchMode, SpaceAround spaceAround)
{
Name = name;
SearchMode = searchMode;
SpaceAround = spaceAround;
}
}
}
@@ -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;
}
}
+12
View File
@@ -0,0 +1,12 @@
namespace YesNt.Interpreter.Enums
{
internal enum Priority
{
Highest,
VeryHigh,
High,
Normal,
Low,
VeryLow
}
}
+10
View File
@@ -0,0 +1,10 @@
namespace YesNt.Interpreter.Enums
{
public enum SearchMode
{
StartOfLine,
EndOfLine,
Contains,
Exact
}
}
+10
View File
@@ -0,0 +1,10 @@
namespace YesNt.Interpreter.Enums
{
public enum SpaceAround
{
StartEnd,
Start,
End,
None
}
}
+12
View File
@@ -0,0 +1,12 @@
namespace YesNt.Interpreter
{
internal class Program
{
private static void Main(string[] args)
{
YesNtInterpreter interpreter = new YesNtInterpreter();
interpreter.Initialize();
interpreter.Execute(args[0]);
}
}
}
@@ -0,0 +1,13 @@
{
"profiles": {
"YesNt-Interpreter": {
"commandName": "Project",
"commandLineArgs": "code.ynt"
},
"WSL": {
"commandName": "WSL2",
"environmentVariables": {},
"distributionName": ""
}
}
}
@@ -0,0 +1,11 @@
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; }
}
}
@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using YesNt.Interpreter.Utilities;
namespace YesNt.Interpreter
{
internal class RuntimeInformation
{
public Dictionary<string, string> Variables { get; } = new();
public Dictionary<string, int> Labels { get; } = new();
public List<string> Lines { get; set; } = new();
public string CurrentLine { get; set; } = string.Empty;
public Stack<int> LabelStack { get; set; } = new();
public string SearchLabel { get; set; } = string.Empty;
public int LineNumber { get; set; } = 0;
public bool Stop { get; private set; } = false;
public bool IsDebugMode { get; set; }
public event Action<string> OnDebugOutput;
public void WriteLine(string output)
{
if (IsDebugMode)
{
OnDebugOutput?.Invoke(output.FromSaveString() + Environment.NewLine);
}
else
{
Console.WriteLine(output.FromSaveString());
}
}
public void Write(string output)
{
if (IsDebugMode)
{
OnDebugOutput?.Invoke(output.FromSaveString());
}
else
{
Console.Write(output.FromSaveString());
}
}
public void Exit(string message)
{
WriteLine($"{Environment.NewLine}[The process was terminated at line {LineNumber + 1} with the message: {message}]");
Stop = true;
}
public void Reset()
{
CurrentLine = string.Empty;
Lines.Clear();
Variables.Clear();
Labels.Clear();
LabelStack.Clear();
SearchLabel = string.Empty;
Stop = false;
IsDebugMode = false;
LineNumber = 0;
}
}
}
@@ -0,0 +1,12 @@
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 bool IgnoreSyntaxHighlighting { get; internal set; }
}
}
@@ -0,0 +1,7 @@
namespace YesNt.Interpreter
{
internal abstract class StatementRuntimeInformation
{
public RuntimeInformation RuntimeInfo { get; set; }
}
}
@@ -0,0 +1,203 @@
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,
IgnoreSyntaxHighlighting = s.Key.IgnoreSyntaxHighlighting
};
}).ToList();
return new ReadOnlyCollection<StatementInformation>(informations);
}
}
public event Action<DebugEventArgs> OnLineExecuted;
public event Action<string> OnDebugOutput;
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);
}
public void Execute(string path, bool isDebugMode = false)
{
runtimeInfo.Reset();
runtimeInfo.IsDebugMode = isDebugMode;
LoadFile(path);
for (runtimeInfo.LineNumber = 0; 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()
};
if (string.IsNullOrWhiteSpace(runtimeInfo.CurrentLine))
{
continue;
}
foreach (KeyValuePair<StaticStatementAttribute, Action> staticStatement in staticStatements)
{
StaticStatementAttribute staticStatementAttribute = staticStatement.Key;
if (staticStatementAttribute.ExecuteInSearchLabelMode == false && !string.IsNullOrWhiteSpace(runtimeInfo.SearchLabel))
{
continue;
}
staticStatement.Value.Invoke();
}
bool statementFound = false;
bool searchingLabel = string.IsNullOrWhiteSpace(runtimeInfo.SearchLabel);
foreach (KeyValuePair<StatementAttribute, Action<string>> statement in statements)
{
StatementAttribute statementAttribute = statement.Key;
if (statementAttribute.ExecuteInSearchLabelMode == false && !string.IsNullOrWhiteSpace(runtimeInfo.SearchLabel))
{
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))
{
runtimeInfo.CurrentLine = $"{runtimeInfo.CurrentLine} ";
string copyLine = statementAttribute.KeepStatementInArgs ? runtimeInfo.CurrentLine : runtimeInfo.CurrentLine.Replace(name, string.Empty);
statement.Value.Invoke(copyLine);
statementFound = true;
}
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");
}
if (isDebugMode && searchingLabel)
{
debugEventArgs.CurrentLine = runtimeInfo.CurrentLine.FromSaveString();
OnLineExecuted?.Invoke(debugEventArgs);
}
}
if (runtimeInfo.Stop == false)
{
runtimeInfo.Exit("End of file");
}
}
private void LoadFile(string path)
{
if (!File.Exists(path))
{
runtimeInfo.WriteLine($"File \"{path}\" not found!");
return;
}
IEnumerable<string> lines = File.ReadAllLines(path);
runtimeInfo.Lines.AddRange(lines);
}
}
}
+199
View File
@@ -0,0 +1,199 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using YesNt.Interpreter.Attributes;
using YesNt.Interpreter.Enums;
using YesNt.Interpreter.Utilities;
namespace YesNt.Interpreter
{
internal class Statements : StatementRuntimeInformation
{
[Statement("cwl", SearchMode.StartOfLine, SpaceAround.End, Priority = Priority.VeryLow)]
public void WriteLine(string args)
{
RuntimeInfo.WriteLine(args);
}
[Statement("cw", SearchMode.StartOfLine, SpaceAround.End, Priority = Priority.VeryLow)]
public void Write(string args)
{
RuntimeInfo.Write(args);
}
[Statement("%crl", SearchMode.Contains, SpaceAround.End, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void ReadLine(string args)
{
args += " ";
while (args.Contains("%crl "))
{
args = args.ReplaceFirstOccurrence("%crl ", Console.ReadLine().ToSaveString() + " ");
}
RuntimeInfo.CurrentLine = args.TrimEnd();
}
[Statement("%cr", SearchMode.Contains, SpaceAround.End, KeepStatementInArgs = true, Priority = Priority.Highest)]
public void ReadKey(string args)
{
args += " ";
while (args.Contains("%cr "))
{
args = args.ReplaceFirstOccurrence("%cr ", Console.ReadKey().KeyChar.ToString().ToSaveString() + " ");
}
RuntimeInfo.CurrentLine = args.TrimEnd();
}
[Statement("jmp", SearchMode.StartOfLine, SpaceAround.End)]
public void Jump(string args)
{
string key = args.Trim();
RuntimeInfo.LabelStack.Push(RuntimeInfo.LineNumber);
if (RuntimeInfo.Labels.ContainsKey(key))
{
RuntimeInfo.LineNumber = RuntimeInfo.Labels[key];
}
else
{
RuntimeInfo.SearchLabel = key;
}
}
[Statement("jif", SearchMode.StartOfLine, SpaceAround.End)]
public void JumpIf(string args)
{
string[] parts = args.Split('|');
if (parts.Length != 2)
{
RuntimeInfo.Exit("Invalid syntax");
return;
}
string key = parts[0].Trim();
string condition = parts[1].Trim();
bool? result = Evaluator.EvaluateCondition(condition);
if (result != true)
{
if (result is null)
{
RuntimeInfo.Exit("Invalid operation");
}
return;
}
RuntimeInfo.LabelStack.Push(RuntimeInfo.LineNumber);
if (RuntimeInfo.Labels.ContainsKey(key))
{
RuntimeInfo.LineNumber = RuntimeInfo.Labels[key];
}
else
{
RuntimeInfo.SearchLabel = key;
}
}
[Statement("lbl", SearchMode.StartOfLine, SpaceAround.End, ExecuteInSearchLabelMode = true)]
public void FindLabel(string args)
{
string key = args.Trim();
if (RuntimeInfo.Labels.ContainsKey(key))
{
RuntimeInfo.Labels[key] = RuntimeInfo.LineNumber;
}
else
{
RuntimeInfo.Labels.Add(key, RuntimeInfo.LineNumber);
}
if (!string.IsNullOrWhiteSpace(RuntimeInfo.SearchLabel) && RuntimeInfo.SearchLabel == key)
{
RuntimeInfo.SearchLabel = string.Empty;
}
}
[Statement("ret", SearchMode.Exact, SpaceAround.None)]
public void Return(string _)
{
if (RuntimeInfo.LabelStack.Count > 0)
{
RuntimeInfo.LineNumber = RuntimeInfo.LabelStack.Pop();
}
else
{
RuntimeInfo.Exit("No label in stack");
}
}
[Statement("end", SearchMode.Exact, SpaceAround.None)]
public void End(string _)
{
RuntimeInfo.Exit("Planned termination by code");
}
[Statement("!calc", SearchMode.EndOfLine, SpaceAround.Start, Priority = Priority.High, ExecuteInSearchLabelMode = true)]
public void Calculate(string args)
{
MatchCollection matches = Regex.Matches(args, @"((\)?)+(\(?)+[0-9]+(((\s?)+(\)?)(\s?)+\+(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\-(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\*(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\/(\s?)+(\(?)+(\s?)+)|[,.])(?=[0-9])+)+[0-9]+(\)?)+");
for (int i = 0; i < matches.Count; i++)
{
string res = Evaluator.Calculate(matches[i].Value);
if (res is null)
{
RuntimeInfo.Exit("Invalid operation");
return;
}
args = args.Replace(matches[0].Value, res);
}
RuntimeInfo.CurrentLine = args;
}
[Statement("!eval", SearchMode.EndOfLine, SpaceAround.Start, Priority = Priority.VeryHigh, ExecuteInSearchLabelMode = true)]
public void Evaluate(string args)
{
RuntimeInfo.CurrentLine = args.FromSaveString();
}
[Statement("<", SearchMode.StartOfLine, SpaceAround.None, Priority = Priority.VeryLow, IgnoreSyntaxHighlighting = true)]
public void DefineVariable(string args)
{
string[] parts = args.Split('=');
if (parts.Length == 2)
{
string key = parts[0].Replace("<", "").Trim();
if (RuntimeInfo.Variables.ContainsKey(key))
{
RuntimeInfo.Variables[key] = parts[1].Trim();
}
else
{
RuntimeInfo.Variables.Add(key, parts[1].Trim());
}
}
else
{
RuntimeInfo.Exit("Invalid syntax");
return;
}
}
[StaticStatement(ExecuteInSearchLabelMode = true)]
public void ReadVariable()
{
if (!RuntimeInfo.CurrentLine.Contains('>'))
{
return;
}
foreach (KeyValuePair<string, string> variable in RuntimeInfo.Variables)
{
RuntimeInfo.CurrentLine = RuntimeInfo.CurrentLine.Replace($">{variable.Key}", variable.Value);
}
}
}
}
+168
View File
@@ -0,0 +1,168 @@
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;
}
/*
((\)?)+(\(?)+[0-9]+(((\s?)+(\)?)(\s?)+\+(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\-(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\*(\s?)+(\(?)+(\s?)+|(\s?)+(\)?)(\s?)+\/(\s?)+(\(?)+(\s?)+)|[,.])(?=[0-9])+)+[0-9]+(\)?)+
*/
public static string Calculate(string input, char op = '+')
{
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>
+357
View File
@@ -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;
}
}
}
+426
View File
@@ -0,0 +1,426 @@
using System;
using System.Collections.Generic;
using System.IO;
using YesNt.Interpreter;
namespace YesNt.CodeEditor
{
internal class TextEditor
{
private readonly YesNtInterpreter yesNtInterpreter = new();
private readonly SyntaxHighlighter syntaxHighlighter;
private int lineOffset = 0;
private readonly List<string> lines = new();
private readonly List<string> debugOutput = new();
private readonly Point cursorPosition = new(0, 0);
private Mode mode = Mode.Command;
private string currentPath = string.Empty;
public TextEditor(string path) : this()
{
if (File.Exists(path))
{
Load(path);
}
}
public TextEditor()
{
yesNtInterpreter.Initialize();
yesNtInterpreter.OnDebugOutput += YesNtInterpreter_OnDebugOutput;
yesNtInterpreter.OnLineExecuted += YesNtInterpreter_OnLineExecuted;
syntaxHighlighter = new(yesNtInterpreter.StatementInformation);
}
public void Run()
{
Console.Clear();
Display(true);
do
{
Display(false);
} while (HandleInput());
}
private void Display(bool drawAll)
{
Console.CursorVisible = false;
Console.SetCursorPosition(0, 0);
int padding = (Console.WindowHeight + lineOffset - 3).ToString().Length;
padding = Math.Max(padding, lines.Count.ToString().Length);
padding += 1;
for (int i = lineOffset; i < Console.WindowHeight + lineOffset - 2; i++)
{
Console.SetCursorPosition(0, i - lineOffset);
string lineCountString = $"{i + 1}".PadRight(padding, ' ') + "| ";
if (i < lines.Count)
{
if (cursorPosition.Y == i || drawAll)
{
Console.Write(lineCountString);
string printLine = $"{lines[i].Substring(0, 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.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 + padding + 2, Console.WindowWidth - 1), cursorPosition.Y - lineOffset);
Console.CursorVisible = true;
}
private bool HandleInput()
{
if (mode == Mode.Edit)
{
ConsoleKeyInfo keyInfo = Console.ReadKey(true);
if ((ConsoleModifiers.Alt & keyInfo.Modifiers) != 0 && keyInfo.Key == ConsoleKey.C)
{
mode = Mode.Command;
}
else if (keyInfo.Key == ConsoleKey.DownArrow)
{
cursorPosition.Y++;
if (cursorPosition.Y - lineOffset >= Console.WindowHeight - 3)
{
lineOffset++;
Display(true);
}
}
else if (keyInfo.Key == ConsoleKey.UpArrow)
{
if (cursorPosition.Y > 0)
{
cursorPosition.Y--;
if (cursorPosition.Y - lineOffset < 0 && lineOffset > 0)
{
lineOffset--;
Display(true);
}
}
}
else if (keyInfo.Key == ConsoleKey.LeftArrow)
{
if (cursorPosition.X > 0)
{
cursorPosition.X--;
}
}
else if (keyInfo.Key == ConsoleKey.RightArrow)
{
if (cursorPosition.X + 6 < Console.WindowWidth - 1)
{
cursorPosition.X++;
}
}
else if (keyInfo.Key == ConsoleKey.Enter)
{
while (lines.Count <= cursorPosition.Y)
{
lines.Add("");
}
lines.Insert(cursorPosition.Y, "");
string line = lines[cursorPosition.Y + 1];
lines[cursorPosition.Y] = line.Substring(0, Math.Min(cursorPosition.X, line.Length));
lines[cursorPosition.Y + 1] = line.Substring(Math.Min(cursorPosition.X, line.Length));
cursorPosition.X = 0;
cursorPosition.Y++;
if (cursorPosition.Y - lineOffset >= Console.WindowHeight - 3)
{
lineOffset++;
}
Display(true);
}
else
{
while (lines.Count <= cursorPosition.Y)
{
lines.Add("");
}
while (lines[cursorPosition.Y].Length <= cursorPosition.X)
{
lines[cursorPosition.Y] += " ";
}
if (keyInfo.Key == ConsoleKey.Backspace)
{
if (cursorPosition.X > 0)
{
lines[cursorPosition.Y] = lines[cursorPosition.Y].Remove(cursorPosition.X - 1, 1);
cursorPosition.X--;
}
else
{
if (cursorPosition.Y > 0)
{
if (string.IsNullOrWhiteSpace(lines[cursorPosition.Y - 1]))
{
lines.RemoveAt(--cursorPosition.Y);
}
else
{
cursorPosition.Y--;
cursorPosition.X = lines[cursorPosition.Y].TrimEnd().Length;
lines[cursorPosition.Y] += lines[cursorPosition.Y + 1];
lines.RemoveAt(cursorPosition.Y + 1);
}
if (cursorPosition.Y - lineOffset < 0 && lineOffset > 0)
{
lineOffset--;
}
Display(true);
}
}
while (lines.Count > 0 && string.IsNullOrWhiteSpace(lines[lines.Count - 1]))
{
lines.RemoveAt(lines.Count - 1);
}
}
else
{
char input = keyInfo.KeyChar;
if (!char.IsControl(input))
{
lines[cursorPosition.Y] = lines[cursorPosition.Y].Insert(cursorPosition.X, input.ToString());
cursorPosition.X++;
}
}
}
}
else if (mode == Mode.Command)
{
Console.SetCursorPosition(3, Console.WindowHeight - 2);
string input = Console.ReadLine() ?? string.Empty;
string command = input.Split(' ')[0].Trim();
string path;
switch (command)
{
case "edit":
WriteStatus(string.Empty);
mode = Mode.Edit;
break;
case "save":
Save(input, false);
break;
case "run":
if (Save(input, true))
{
Console.Clear();
yesNtInterpreter.Execute(currentPath);
Console.ReadKey();
}
break;
case "debug":
if (Save(input, true))
{
Console.Clear();
yesNtInterpreter.Execute(currentPath, true);
Console.ReadKey();
WriteStatus(string.Empty);
}
break;
case "load":
if (input.Split(' ').Length == 2)
{
path = input.Split(' ')[1];
}
else
{
WriteStatus("Invalid arguments!");
break;
}
if (!File.Exists(path))
{
WriteStatus("File does not exist!");
break;
}
try
{
Load(path);
}
catch (Exception ex)
{
WriteStatus(ex.Message);
}
lineOffset = 0;
cursorPosition.X = 0;
cursorPosition.Y = 0;
break;
case "new":
if (Save(input, false))
{
lineOffset = 0;
cursorPosition.X = 0;
cursorPosition.Y = 0;
currentPath = string.Empty;
lines.Clear();
WriteStatus(string.Empty);
}
break;
case "exit":
return false;
default:
WriteStatus("Command not found!");
break;
}
Display(true);
}
return true;
}
private bool Load(string path)
{
if (!File.Exists(path))
{
WriteStatus("File does not exist!");
return false;
}
lines.Clear();
foreach (string line in File.ReadAllLines(path))
{
lines.Add(line.Replace("\n", ""));
}
currentPath = path;
WriteStatus("File Loaded!");
return true;
}
private bool Save(string input, bool loadIfExists)
{
string text = "";
string path = "";
foreach (string line in lines)
{
text += line + "\n";
}
text = text.TrimEnd('\n');
if (input.Split(' ').Length == 2)
{
path = input.Split(' ')[1];
if (currentPath.Trim() != path.Trim() && loadIfExists)
{
if (Load(path))
{
return true;
}
else
{
return false;
}
}
currentPath = path;
}
else if (!string.IsNullOrWhiteSpace(currentPath))
{
path = currentPath;
}
else if (input.Split(' ').Length > 2)
{
WriteStatus("Invalid arguments!");
return false;
}
else
{
WriteStatus("File path is empty!");
return false;
}
try
{
File.WriteAllText(path, text);
WriteStatus("File Saved!");
return true;
}
catch (Exception ex)
{
WriteStatus(ex.Message);
return false;
}
}
private void WriteStatus(string input)
{
Console.SetCursorPosition(0, Console.WindowHeight - 1);
Console.Write(input + new string(' ', Console.WindowWidth - input.Length - 1));
}
private void YesNtInterpreter_OnDebugOutput(string output)
{
debugOutput.Add(output);
}
private void YesNtInterpreter_OnLineExecuted(Interpreter.Runtime.DebugEventArgs e)
{
Console.ForegroundColor = ConsoleColor.Magenta;
if (e.OriginalLine == e.CurrentLine)
{
Console.WriteLine($"{Environment.NewLine}[{e.LineNumber}] [{e.CurrentLine}] ==>");
}
else
{
Console.WriteLine($"{Environment.NewLine}[{e.LineNumber}] [{e.OriginalLine}] => [{e.CurrentLine}] ==>");
}
Console.ResetColor();
foreach (string output in debugOutput)
{
Console.Write(output);
}
debugOutput.Clear();
}
}
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
}
}
+29
View File
@@ -0,0 +1,29 @@
using System;
namespace YesNt.CodeEditor
{
internal class Program
{
private static void Main(string[] args)
{
TextEditor textEditor;
Console.CancelKeyPress += Console_CancelKeyPress;
if (args.Length > 0)
{
textEditor = new TextEditor(args[0]);
}
else
{
textEditor = new TextEditor();
}
textEditor.Run();
}
private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
e.Cancel = true;
}
}
}
+107
View File
@@ -0,0 +1,107 @@
using System;
using System.Collections.ObjectModel;
using System.Text.RegularExpressions;
using YesNt.Interpreter.Enums;
using YesNt.Interpreter.Runtime;
using YesNt.Interpreter.Utilities;
namespace YesNt.CodeEditor
{
internal class SyntaxHighlighter
{
private ReadOnlyCollection<StatementInformation> statementInformation;
public SyntaxHighlighter(ReadOnlyCollection<StatementInformation> statementInformation)
{
this.statementInformation = statementInformation;
}
public void Write(string input)
{
input = input.Replace("\0", string.Empty);
foreach (StatementInformation statement in statementInformation)
{
if (statement.IgnoreSyntaxHighlighting)
{
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))
{
input = AddColorInformation(input, input.Substring(0, name.Length), ConsoleColor.DarkGreen, statement.SearchMode);
}
if (statement.SearchMode == SearchMode.Contains && $"{input} ".Contains(name))
{
input = AddColorInformation($"{input} ", $"{input} ".Substring($"{input} ".IndexOf(name), name.Length), ConsoleColor.Green, statement.SearchMode);
}
if (statement.SearchMode == SearchMode.EndOfLine && input.EndsWith(name))
{
input = AddColorInformation(input, input.Substring(input.Length - name.Length), ConsoleColor.DarkYellow, statement.SearchMode);
}
if (statement.SearchMode == SearchMode.Exact && input.Equals(name))
{
input = AddColorInformation(input, input, ConsoleColor.Red, statement.SearchMode);
}
}
MatchCollection matches = Regex.Matches(input, @">[a-zA-Z0-9]+");
for (int i = 0; i < matches.Count; i++)
{
input = AddColorInformation(input, matches[i].Value, ConsoleColor.Cyan, SearchMode.Contains);
}
matches = Regex.Matches(input, @"^<[a-zA-Z0-9]+");
for (int i = 0; i < matches.Count; i++)
{
input = AddColorInformation(input, matches[i].Value, ConsoleColor.DarkCyan, SearchMode.StartOfLine);
}
foreach (string part in input.Split("\0"))
{
ConsoleColor consoleColor;
string messagePart = part;
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;
}
if (consoleColor == Console.BackgroundColor || consoleColor == ConsoleColor.DarkGray)
{
consoleColor = ConsoleColor.White;
}
Console.ForegroundColor = consoleColor;
Console.Write(messagePart, consoleColor);
Console.ResetColor();
}
}
private 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;
}
}
}
+12
View File
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\YesNt-Interpreter\YesNt.Interpreter.csproj" />
</ItemGroup>
</Project>