make this work under linux lol

This commit is contained in:
Qrakhen 2026-05-08 00:54:08 +02:00
parent 44b8bb8900
commit 1da47d39dd
19 changed files with 251 additions and 42 deletions

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) [2025] [David Neumaier, Qrakhen] Copyright (c) [2026] [David Neumaier, Qrakhen]
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -0,0 +1,27 @@
namespace Qrakhen.Qamp.CLI;
[Flags]
public enum ConsoleMods
{
None = 0,
Red = 1,
Green = 2,
Blue = 4,
Yellow = Red | Green,
White = Red | Green | Blue,
Color = 1 << 10,
Bold = 1 << 20,
Italic = 1 << 21,
Underlined = 1 << 22,
Clear = 1 << 31,
}
public interface IConsolePainter
{
ConsoleMods Mods { get; set; }
}

View File

@ -1,9 +1,13 @@
using Qrakhen.Qamp.Core; using Qrakhen.Qamp.Core;
using Qrakhen.Qamp.Core.Execution; using Qrakhen.Qamp.Core.Execution;
using Qrakhen.Qamp.Core.Logging; using Qrakhen.Qamp.Core.Logging;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
List<char> Ignored = [ '\0', '\b' ]; List<char> Ignored = [ '\0', '\b' ];
Benchmark.Active = false;
LoggerService.Default = LogLevel.Error; LoggerService.Default = LogLevel.Error;
List<byte[]> History = []; List<byte[]> History = [];
int historyCursor = -1; int historyCursor = -1;
@ -12,10 +16,59 @@ bool useSyntaxHighlighting = false;
(int x, int y) cursor = (0, 0); (int x, int y) cursor = (0, 0);
ConsoleCode code = ConsoleCode.Error; ConsoleCode code = ConsoleCode.Error;
Runner runner = new(new Options()); Runner runner = new(new Options());
Stream stdOut = Console.OpenStandardOutput();
Stream stdErr = Console.OpenStandardError();
Stream stdIn = Console.OpenStandardInput();
void write(string what, Stream stream) => stream.Write(Encoding.Default.GetBytes(what));
string[] flags = args.Where(x => x.StartsWith("-")).Select(x => x[1..]).ToArray();
string[] files = args.Where(x => !x.StartsWith("-")).ToArray();
if (flags.IndexOf("h") > 0)
{
write(" :: Q& Help.\n", stdOut);
write(" Basic usage: qamp {FILES} {OPTIONS}\n", stdOut);
write(" Flags:\n", stdOut);
write(" -i --interactive \n", stdOut);
write(" -n --nurture \n", stdOut);
write(" -l --log-level=<int> \n", stdOut);
write(" -d --dialect=<sqr|default>\n", stdOut);
write(" Example: qamp ~/myNiceScript.qp -i -n -l=0\n", stdOut);
return (int)QRESULT.OK;
}
if (files.Length > 0)
{
foreach (var file in files)
{
if (File.Exists(file))
{
var result = runner.Run(File.OpenRead(file));
write($" :: {file}: {result.RunnerResult} ({result.Returned})\n", stdOut);
}
else
{
write($"Could not find file located at '{file}'.\n", stdErr);
return (int)QRESULT.NOT_FOUND;
}
}
}
if (flags.IndexOf("i") < 0 && files.Length > 0)
{
return (int)QRESULT.OK;
}
if (flags.IndexOf("i") < 0)
{
write(" :: Assuming interactive mode (-i).\n :: If that is intended, use qamp -i to prevent this notification.\n", stdOut);
}
do { do {
Console.ForegroundColor = ConsoleColor.White; Console.ForegroundColor = ConsoleColor.White;
MemoryStream stream = new MemoryStream(); MemoryStream stream = new MemoryStream();
Console.Write(" <: "); write(" <: ", stdOut);
cursor = Console.GetCursorPosition(); cursor = Console.GetCursorPosition();
do { do {
if (useSyntaxHighlighting) if (useSyntaxHighlighting)
@ -25,12 +78,22 @@ do {
if (input.Modifiers == ConsoleModifiers.Control) { if (input.Modifiers == ConsoleModifiers.Control) {
if (input.Key == ConsoleKey.H) { if (input.Key == ConsoleKey.H) {
useSyntaxHighlighting = !useSyntaxHighlighting; useSyntaxHighlighting = !useSyntaxHighlighting;
Console.Write($"\n #: {nameof(useSyntaxHighlighting)} = {useSyntaxHighlighting}\n <: "); //write(Colors.ColorText($"\n #: {nameof(useSyntaxHighlighting)} = {useSyntaxHighlighting}\n <: ", 30));
write($"\n #: {nameof(useSyntaxHighlighting)} = {useSyntaxHighlighting}\n <: ", stdOut);
cursor = Console.GetCursorPosition(); cursor = Console.GetCursorPosition();
} }
if (input.Key == ConsoleKey.B) {
Benchmark.Active = !Benchmark.Active;
//write(Colors.ColorText($"\n #: {nameof(Benchmark)}.{nameof(Benchmark.Active)} = {Benchmark.Active}\n <: ", 30));
write($"\n #: {nameof(Benchmark)}.{nameof(Benchmark.Active)} = {Benchmark.Active}\n <: ", stdOut);
cursor = Console.GetCursorPosition();
}
if (input.Key == ConsoleKey.L) { if (input.Key == ConsoleKey.L) {
LoggerService.Default = LoggerService.Default < LogLevel.All ? LogLevel.All : LogLevel.Info; LoggerService.Default = LoggerService.Default < LogLevel.All ? LogLevel.All : LogLevel.Info;
Console.Write($"\n #: LogLevel = {LoggerService.Default}\n <: "); //write(Colors.ColorText($"\n #: LogLevel = {LoggerService.Default}\n <: ", 30));
write($"\n #: LogLevel = {LoggerService.Default}\n <: ", stdOut);
cursor = Console.GetCursorPosition(); cursor = Console.GetCursorPosition();
} }
continue; continue;
@ -106,6 +169,42 @@ do {
} }
} while (code != ConsoleCode.Exit); } while (code != ConsoleCode.Exit);
return (int)QRESULT.OK;
// yes i'm making these up, just like anyone else
public enum QRESULT
{
OK = 0,
INVALID_ARGS = 0x14,
SYNTAX_ERROR = 0x72,
NOT_FOUND = 0x204
}
// leenux colors
public static class Colors
{
private readonly static int cBlack = 0,
cRed = 1,
cGreen = 2,
cYellow = 3,
cCyan = 4,
cPink = 5,
cCyanD = 6,
cWhite = 7;
private readonly static int fBack = 40,
fFore = 30;
private static string Wrap(int code) => @$"\e[{code}m";
// goote goute
public static string ColorText(string text, params int[] codes) =>
string.Join("", codes.Select(c => Wrap(c))) + text + Wrap(0);
public static string Red { get; } = Wrap(fFore + cRed);
}
public class Command public class Command
{ {

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<BaseOutputPath>..\Build\</BaseOutputPath> <BaseOutputPath>..\Build\</BaseOutputPath>

14
Qrakhen.Qamp.CLI/test.qp Normal file
View File

@ -0,0 +1,14 @@
print("\nQ& Test script.");
*~ how <~ 'very cool';
var _WHAT_ = "ABQ&%$#@!";
var a = 7;
*~ b <~ 12;
var c <~ 8;
*~ d = 3;
:: _WHAT_.SubString(2, 2) + ' is ' + how;
print(a * b * c * d);
:: "if you can read this, Q& probably works. Wow."

View File

@ -0,0 +1,24 @@
using System.Text;
using Qrakhen.Qamp.Core.Execution;
namespace Qrakhen.Qamp.Core.Tests;
public class CodeTest
{
private readonly Runner _runner = new(new Options());
private RunnerResult ExecuteCode(string code)
{
using Stream stream = new MemoryStream();
stream.Write(Encoding.UTF8.GetBytes(code));
return _runner.Run(stream);
}
[Fact]
public void VariableDeclaration_Empty_AllocatesName()
{
string code = "var name;";
var result = ExecuteCode(code);
}
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
@ -15,6 +15,10 @@
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" /> <PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="../Qrakhen.Qamp.Core/Qrakhen.Qamp.Core.csproj" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Using Include="Xunit" /> <Using Include="Xunit" />
</ItemGroup> </ItemGroup>

View File

@ -1,10 +0,0 @@
namespace Qrakhen.Qamp.Core.Tests;
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}

View File

@ -76,7 +76,6 @@ public class Digester : ISteppable<Token>
public Function Digest() public Function Digest()
{ {
Benchmark.Active = true;
Benchmark.Start($"Digest begin"); Benchmark.Start($"Digest begin");
#if LOG #if LOG
_logger.Method(); _logger.Method();

View File

@ -77,6 +77,8 @@ public class Runner : IDisposable
private readonly ILogger _logger = LoggerService.Get<Runner>(); private readonly ILogger _logger = LoggerService.Get<Runner>();
private readonly OperationRouter _router = new OperationRouter(); private readonly OperationRouter _router = new OperationRouter();
private Value _runnerReturned = Value.Void;
public readonly Options Options; public readonly Options Options;
private List<IOperationResolver> _resolvers = []; private List<IOperationResolver> _resolvers = [];
@ -103,36 +105,52 @@ public class Runner : IDisposable
_router.Register(new ArithmeticResolver()); _router.Register(new ArithmeticResolver());
} }
public ExecutionResult Run(Stream stream) public ExecutionResult Run(Stream stream, params string[] parameters)
{ {
#if LOG _logger.Method();
_logger.Method();
#endif
if (_stack.Position != 0) { if (_stack.Position != 0) {
#if LOG _logger.Warn($"Something went terribly wrong, stack cursor is at {_stack.Position} before execution.\n --- Resetting Stack ---");
_logger.Warn($"Something went wrong, stack cursor is at {_stack.Position}. Resetting Stack.");
#endif
_stack = new StackLike<Value>(Options.InitialStackSize); _stack = new StackLike<Value>(Options.InitialStackSize);
} }
DateTime start = DateTime.Now;
Benchmark.Start($"Compile Start"); Benchmark.Start($"Compile Start");
// cached value, used to directly return resulting values to the calling process
_runnerReturned = Value.Void;
using Reader reader = new Reader(stream); using Reader reader = new Reader(stream);
Compilation.Digester digester = new(reader); Compilation.Digester digester = new(reader);
Function function = digester.Digest(); Function function = digester.Digest();
Benchmark.End($"Compile End"); Benchmark.End($"Compile End");
// compilation result taste test
if (stream.Length > 64) if (stream.Length > 64)
File.WriteAllBytes($"./func.{DateTime.Now:yyyyMMdd_HHmmss}.sqi", function.Serialize(true)); File.WriteAllBytes($"./func.{DateTime.Now:yyyyMMdd_HHmmss}.sqi", function.Serialize(true));
// run the code in a new context.
// global namespace bleeds into here anyway, executing directly in global namespace is a 'safety risk'.
Context closure = new Context(function); Context closure = new Context(function);
Push(Obj.Create(closure)); Push(Obj.Create(closure));
Invoke(closure, 0); Invoke(closure, 0);
Benchmark.Start($"Execution Start"); Benchmark.Start($"Execution Start");
ExecutionResult result = Execute(); RunnerResult result = Execute();
Benchmark.End($"Execution End"); Benchmark.End($"Execution End");
return result;
DateTime end = DateTime.Now;
return new ExecutionResult(result,
_runnerReturned,
start,
end,
parameters);
} }
private bool TestHandler(Op code, Op handler) => (code & Op.Mask_Handler) == handler; private bool TestHandler(Op code, Op handler) => (code & Op.Mask_Handler) == handler;
private ExecutionResult Execute() private RunnerResult Execute()
{ {
#if LOG #if LOG
_logger.Method(); _logger.Method();
@ -426,7 +444,7 @@ public class Runner : IDisposable
} else { } else {
_logger.Warn($"Critical issue at end of execution detected - stack was empty at return."); _logger.Warn($"Critical issue at end of execution detected - stack was empty at return.");
} }
return ExecutionResult.OK; return RunnerResult.OK;
} }
_stack.Decimate(call.StackPtr.Cursor); _stack.Decimate(call.StackPtr.Cursor);
Push(result); Push(result);
@ -500,7 +518,7 @@ public class Runner : IDisposable
} while (call.Instruction.Segment.Instructions.Length > call.Instruction.Cursor); } while (call.Instruction.Segment.Instructions.Length > call.Instruction.Cursor);
return ExecutionResult.OK; return RunnerResult.OK;
} }
private Outer CaptureOuter(Pointer<Value> target) private Outer CaptureOuter(Pointer<Value> target)
@ -684,7 +702,7 @@ public class Runner : IDisposable
_stack.Push(value); _stack.Push(value);
} }
private ExecutionResult Error(string message, object? context = null, bool @throw = true) private RunnerResult Error(string message, object? context = null, bool @throw = true)
{ {
#if LOG #if LOG
_logger.Method(message); _logger.Method(message);
@ -695,7 +713,7 @@ public class Runner : IDisposable
Panic(); Panic();
if (@throw) if (@throw)
throw new QampException(message, context); throw new QampException(message, context);
return ExecutionResult.Execution; return RunnerResult.Execution;
} }
private void Panic() private void Panic()
@ -719,12 +737,35 @@ public class GarbageCollector
} }
public enum ExecutionResult public enum RunnerResult
{ {
OK = 0x0000, OK = 0x0000,
Error = 0x1000, Error = 0x1000,
Compilation = Error | 0x0001, Compilation = 0x0001,
Execution = Error | 0x0002 Execution = 0x0002,
Unknown = -1
}
public readonly struct ExecutionResult(
RunnerResult code = RunnerResult.Unknown,
Value? returned = null,
DateTime? started = null,
DateTime? finished = null,
string[] parameters = null)
{
public RunnerResult RunnerResult { get; } = code;
public Value? Returned { get; } = returned;
public DateTime Started { get; } = started ?? DateTime.Now;
public DateTime Finished { get; } = finished ?? DateTime.Now;
public string[] Parameters { get; } = parameters ?? [];
public bool Success => RunnerResult == RunnerResult.OK;
public bool HasValue => Returned?.Type != T.Void;
public TimeSpan Elapsed => Finished - Started;
} }
public readonly struct Options( public readonly struct Options(

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>

View File

@ -223,13 +223,19 @@ public static class StringExtensions
public static long IndexOf(Value self, Value needle) public static long IndexOf(Value self, Value needle)
{ {
string _self = self.Ptr.As<Objects.String>()?.Value ?? ""; string _self = self.Ptr.As<Objects.String>()?.Value ?? "";
string _needle = self.Ptr.As<Objects.String>()?.Value ?? ""; string _needle = needle.Ptr.As<Objects.String>()?.Value ?? "";
if (_needle.Length < 1 || _self.Length < 1) if (_needle.Length < 1 || _self.Length < 1)
return -1; return -1;
return _self.IndexOf(_needle); return _self.IndexOf(_needle);
} }
[ExtensionMethod]
public static Value SubString(Value self, Value start, Value length)
{
return self.Ptr.As<Objects.String>()?.SubString(start, length) ?? Value.Void;
}
[ExtensionMethod] [ExtensionMethod]
public static Objects.Array Split(Value self, Value splitter) public static Objects.Array Split(Value self, Value splitter)
{ {

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<BaseOutputPath>..\Build\</BaseOutputPath> <BaseOutputPath>..\Build\</BaseOutputPath>

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net10.0-windows</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<BaseOutputPath>..\Build\</BaseOutputPath> <BaseOutputPath>..\Build\</BaseOutputPath>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<BaseOutputPath>..\Build\</BaseOutputPath> <BaseOutputPath>..\Build\</BaseOutputPath>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>

5
debug Executable file
View File

@ -0,0 +1,5 @@
#!/bin/bash
DEST='net10.0'
echo "\e[5mBeelding for dotnet version $DEST like it's not a big deal.\e[0m"
dotnet build ./Qrakhen.Qamp.CLI/ && ./Build/Debug/net10.0/Qrakhen.Qamp.CLI -i ./Qrakhen.Qamp.CLI/test.qp