mirror of
https://github.com/Stone-Red-Code/YesNt-Interpreter.git
synced 2026-09-04 00:56:31 +02:00
Initial commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
+334
@@ -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/
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user