From a39096014c563ba9b4c4d86fdd1a4c8a5b6210f7 Mon Sep 17 00:00:00 2001 From: Qrakhen Date: Sun, 23 Nov 2025 07:38:22 +0100 Subject: [PATCH] fix formatting everywhere and make operation resolving faster --- Qrakhen.Qamp.CLI/ConsoleCode.cs | 6 +- Qrakhen.Qamp.CLI/ConsoleExtensions.cs | 14 +- Qrakhen.Qamp.CLI/ConsoleRenderer.cs | 96 +- Qrakhen.Qamp.CLI/ConsoleWriter.cs | 242 +-- Qrakhen.Qamp.CLI/Program.cs | 200 ++- Qrakhen.Qamp.CLI/_Program.cs | 66 +- Qrakhen.Qamp.Core.Tests/UnitTest1.cs | 8 +- Qrakhen.Qamp.Core/Abstractions/IDebug.cs | 20 +- Qrakhen.Qamp.Core/Abstractions/ISerialize.cs | 4 +- Qrakhen.Qamp.Core/Assert.cs | 76 +- Qrakhen.Qamp.Core/Benchmark.cs | 122 +- .../Collections/Abstractions/IAdd.cs | 2 +- .../Abstractions/ICapturableBuffer.cs | 6 +- .../Collections/Abstractions/IConsumable.cs | 2 +- .../Collections/Abstractions/IGet.cs | 2 +- .../Collections/Abstractions/IPeekable.cs | 2 +- .../Collections/Abstractions/IReadable.cs | 4 +- .../Collections/Abstractions/IReader.cs | 6 +- .../Collections/Abstractions/ISeekable.cs | 4 +- .../Collections/Abstractions/ISet.cs | 4 +- .../Collections/Abstractions/IStack.cs | 4 +- .../Collections/Abstractions/ISteppable.cs | 4 +- .../Collections/Abstractions/IToArray.cs | 2 +- Qrakhen.Qamp.Core/Collections/Expander.cs | 92 +- Qrakhen.Qamp.Core/Collections/FixedArray.cs | 44 +- Qrakhen.Qamp.Core/Collections/Pointer.cs | 78 +- Qrakhen.Qamp.Core/Collections/PopStack.cs | 44 +- Qrakhen.Qamp.Core/Collections/PushStack.cs | 82 +- Qrakhen.Qamp.Core/Collections/Register.cs | 52 +- Qrakhen.Qamp.Core/Collections/StackLike.cs | 66 +- .../Compilation/Builders/Builder.cs | 22 +- .../Compilation/Builders/ClassBuilder.cs | 6 +- .../Compilation/Builders/FunctionBuilder.cs | 18 +- .../Compilation/Builders/IBuilder.cs | 2 +- .../Compilation/Builders/SegmentBuilder.cs | 55 +- Qrakhen.Qamp.Core/Compilation/Digester.cs | 1361 +++++++++-------- .../Compilation/Digesters/IDigester.cs | 2 +- .../Compilation/ExpressionParser.cs | 589 +++---- Qrakhen.Qamp.Core/Compilation/Rule.cs | 6 +- Qrakhen.Qamp.Core/Compilation/Weight.cs | 22 +- Qrakhen.Qamp.Core/Console.cs | 14 +- Qrakhen.Qamp.Core/Exceptions.cs | 12 +- Qrakhen.Qamp.Core/Execution/Instruction.cs | 18 +- Qrakhen.Qamp.Core/Execution/InstructionPtr.cs | 90 +- Qrakhen.Qamp.Core/Execution/Instructions.cs | 42 +- Qrakhen.Qamp.Core/Execution/OpCode.cs | 142 +- Qrakhen.Qamp.Core/Execution/Runner.cs | 1070 ++++++------- Qrakhen.Qamp.Core/Execution/Segment.cs | 134 +- Qrakhen.Qamp.Core/Execution/ValueOperation.cs | 4 - Qrakhen.Qamp.Core/Extensions.cs | 166 +- Qrakhen.Qamp.Core/Injector.cs | 12 +- Qrakhen.Qamp.Core/Logging/ILogger.cs | 201 ++- Qrakhen.Qamp.Core/Tokenization/Dialect.cs | 184 +-- Qrakhen.Qamp.Core/Tokenization/Reader.cs | 652 ++++---- Qrakhen.Qamp.Core/Tokenization/Token.cs | 38 +- Qrakhen.Qamp.Core/Tokenization/TokenType.cs | 40 +- Qrakhen.Qamp.Core/Tokenization/Tokens.cs | 17 +- Qrakhen.Qamp.Core/Values/Address.cs | 6 +- Qrakhen.Qamp.Core/Values/NativeExtension.cs | 70 +- Qrakhen.Qamp.Core/Values/Objects/Array.cs | 54 +- Qrakhen.Qamp.Core/Values/Objects/Class.cs | 12 +- Qrakhen.Qamp.Core/Values/Objects/Context.cs | 6 +- Qrakhen.Qamp.Core/Values/Objects/Extension.cs | 10 +- Qrakhen.Qamp.Core/Values/Objects/Function.cs | 34 +- Qrakhen.Qamp.Core/Values/Objects/Instance.cs | 26 +- .../Values/Objects/ItemProvider.cs | 32 +- Qrakhen.Qamp.Core/Values/Objects/List.cs | 76 +- Qrakhen.Qamp.Core/Values/Objects/Method.cs | 2 +- Qrakhen.Qamp.Core/Values/Objects/Native.cs | 8 +- Qrakhen.Qamp.Core/Values/Objects/Obj.cs | 18 +- Qrakhen.Qamp.Core/Values/Objects/Outer.cs | 49 +- Qrakhen.Qamp.Core/Values/Objects/String.cs | 70 +- Qrakhen.Qamp.Core/Values/Objects/Structure.cs | 52 +- Qrakhen.Qamp.Core/Values/Ptr.cs | 106 +- Qrakhen.Qamp.Core/Values/Ref.cs | 4 +- Qrakhen.Qamp.Core/Values/Value.cs | 216 +-- Qrakhen.Qamp.Core/Values/ValueExtensions.cs | 2 +- Qrakhen.Qamp.Core/Values/ValueType.cs | 56 +- Qrakhen.Qamp.Editor/App.xaml.cs | 14 +- .../Commands/MoveCaretOptions.cs | 4 +- Qrakhen.Qamp.Editor/Commands/RelayCommand.cs | 32 +- Qrakhen.Qamp.Editor/Controls/Caret.cs | 74 +- .../Controls/EditorFrame.xaml.cs | 9 +- Qrakhen.Qamp.Editor/InputService.cs | 138 +- Qrakhen.Qamp.Editor/MainWindow.xaml.cs | 8 +- .../Primitives/BufferPosition.cs | 22 +- .../Primitives/BufferRegion.cs | 11 +- Qrakhen.Qamp.Editor/TextHelper.cs | 40 +- .../ViewModel/EditorFrameViewModel.cs | 23 +- .../ViewModel/MainViewModel.cs | 2 +- .../ViewModel/ObservableObject.cs | 26 +- Qrakhen.Qamp.Memory/LineBuffer.cs | 66 +- Qrakhen.Qamp.Memory/TailBuffer.cs | 144 +- Qrakhen.Qamp.Tests/UnitTest1.cs | 8 +- 94 files changed, 3941 insertions(+), 3862 deletions(-) diff --git a/Qrakhen.Qamp.CLI/ConsoleCode.cs b/Qrakhen.Qamp.CLI/ConsoleCode.cs index 60fee39..279f21e 100644 --- a/Qrakhen.Qamp.CLI/ConsoleCode.cs +++ b/Qrakhen.Qamp.CLI/ConsoleCode.cs @@ -1,6 +1,6 @@ public enum ConsoleCode { - Error = -1, - OK = 0, - Exit = 1 + Error = -1, + OK = 0, + Exit = 1 } diff --git a/Qrakhen.Qamp.CLI/ConsoleExtensions.cs b/Qrakhen.Qamp.CLI/ConsoleExtensions.cs index 39a053c..bced478 100644 --- a/Qrakhen.Qamp.CLI/ConsoleExtensions.cs +++ b/Qrakhen.Qamp.CLI/ConsoleExtensions.cs @@ -1,10 +1,10 @@ public static class ConsoleExtensions { - public static bool Check(this ConsoleKeyInfo keyInfo, ConsoleKey key, ConsoleModifiers modifier = default, bool exactModifier = false) - { - return ((exactModifier ? - keyInfo.Modifiers == modifier : - (keyInfo.Modifiers & modifier) == modifier) - && keyInfo.Key == key); - } + public static bool Check(this ConsoleKeyInfo keyInfo, ConsoleKey key, ConsoleModifiers modifier = default, bool exactModifier = false) + { + return ((exactModifier ? + keyInfo.Modifiers == modifier : + (keyInfo.Modifiers & modifier) == modifier) + && keyInfo.Key == key); + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.CLI/ConsoleRenderer.cs b/Qrakhen.Qamp.CLI/ConsoleRenderer.cs index 1c3c906..bde8988 100644 --- a/Qrakhen.Qamp.CLI/ConsoleRenderer.cs +++ b/Qrakhen.Qamp.CLI/ConsoleRenderer.cs @@ -4,54 +4,54 @@ using System.Text; public class ConsoleRenderer { - private readonly IReader _reader; - private readonly Stream _stream; + private readonly IReader _reader; + private readonly Stream _stream; - public ConsoleRenderer(Stream stream) - { - _stream = new MemoryStream(); - stream.Position = 0; - stream.CopyTo(_stream); - _reader = new Reader(_stream); - } + public ConsoleRenderer(Stream stream) + { + _stream = new MemoryStream(); + stream.Position = 0; + stream.CopyTo(_stream); + _reader = new Reader(_stream); + } - public void Render((int x, int y) position) - { - Console.CursorVisible = false; - Console.SetCursorPosition(position.x, position.y); - List tokens = []; - while (!_reader.Done) { - tokens.Add(_reader.NextToken(true)); - } - _stream.Position = 0; - foreach (var token in tokens) { - ConsoleColor color = ConsoleColor.Gray; - if (token.Type.IsBoolean()) - color = ConsoleColor.Blue; - if (token.Type.IsString()) - color = ConsoleColor.Cyan; - if (token.Type.IsNumber()) - color = ConsoleColor.DarkCyan; - if (token.Type.IsOperator()) - color = ConsoleColor.DarkGreen; - if (token.Type.IsBracket()) - color = ConsoleColor.Red; - if (token.Type.IsIdentifier()) - color = ConsoleColor.White; - if (token.Type.IsControl()) - color = ConsoleColor.DarkYellow; - if (token.Type == TokenType.Error) - color = ConsoleColor.DarkRed; - Console.ForegroundColor = color; - byte[] buffer = new byte[token.Span.Length]; - _stream.ReadExactly(buffer, 0, (int)token.Span.Length); - string str = Encoding.Default.GetString(buffer); - Console.Write(str); - Console.ForegroundColor = ConsoleColor.White; - if (token.Type == TokenType.NewLine) - Console.Write(" : "); - } - Console.ForegroundColor = ConsoleColor.White; - Console.CursorVisible = true; - } + public void Render((int x, int y) position) + { + Console.CursorVisible = false; + Console.SetCursorPosition(position.x, position.y); + List tokens = []; + while (!_reader.Done) { + tokens.Add(_reader.NextToken(true)); + } + _stream.Position = 0; + foreach (var token in tokens) { + ConsoleColor color = ConsoleColor.Gray; + if (token.Type.IsBoolean()) + color = ConsoleColor.Blue; + if (token.Type.IsString()) + color = ConsoleColor.Cyan; + if (token.Type.IsNumber()) + color = ConsoleColor.DarkCyan; + if (token.Type.IsOperator()) + color = ConsoleColor.DarkGreen; + if (token.Type.IsBracket()) + color = ConsoleColor.Red; + if (token.Type.IsIdentifier()) + color = ConsoleColor.White; + if (token.Type.IsControl()) + color = ConsoleColor.DarkYellow; + if (token.Type == TokenType.Error) + color = ConsoleColor.DarkRed; + Console.ForegroundColor = color; + byte[] buffer = new byte[token.Span.Length]; + _stream.ReadExactly(buffer, 0, (int)token.Span.Length); + string str = Encoding.Default.GetString(buffer); + Console.Write(str); + Console.ForegroundColor = ConsoleColor.White; + if (token.Type == TokenType.NewLine) + Console.Write(" : "); + } + Console.ForegroundColor = ConsoleColor.White; + Console.CursorVisible = true; + } } diff --git a/Qrakhen.Qamp.CLI/ConsoleWriter.cs b/Qrakhen.Qamp.CLI/ConsoleWriter.cs index 0693014..fce89e9 100644 --- a/Qrakhen.Qamp.CLI/ConsoleWriter.cs +++ b/Qrakhen.Qamp.CLI/ConsoleWriter.cs @@ -2,141 +2,141 @@ public class ConsoleWriter { - private const string SYMBOL_INPUT = " <: "; - private const string SYMBOL_INPUT_CONTINUE = " : "; + private const string SYMBOL_INPUT = " <: "; + private const string SYMBOL_INPUT_CONTINUE = " : "; - private readonly List _buffer = []; - private readonly Stack _history = []; - private readonly Encoding _encoding; + private readonly List _buffer = []; + private readonly Stack _history = []; + private readonly Encoding _encoding; - private int _position; - private (int x, int y) _origin; - private (int x, int y) _cursorPosition => Console.GetCursorPosition(); + private int _position; + private (int x, int y) _origin; + private (int x, int y) _cursorPosition => Console.GetCursorPosition(); - private int _cursorOffset => SYMBOL_INPUT.Length; - private int _cursorLeft { get => Console.CursorLeft; set => Console.CursorLeft = value; } - private int _cursorTop { get => Console.CursorTop; set => Console.CursorTop = value; } + private int _cursorOffset => SYMBOL_INPUT.Length; + private int _cursorLeft { get => Console.CursorLeft; set => Console.CursorLeft = value; } + private int _cursorTop { get => Console.CursorTop; set => Console.CursorTop = value; } - public bool UseSyntaxHighlighting { get; set; } = false; + public bool UseSyntaxHighlighting { get; set; } = false; - public ConsoleWriter(Encoding encoding) - { - _encoding = encoding; - } + public ConsoleWriter(Encoding encoding) + { + _encoding = encoding; + } - private void Write(char c) => Console.Write(c); - private void Write(string str) => Console.Write(str); - private void SetCursor((int x, int y) position) => Console.SetCursorPosition(position.x, position.y); + private void Write(char c) => Console.Write(c); + private void Write(string str) => Console.Write(str); + private void SetCursor((int x, int y) position) => Console.SetCursorPosition(position.x, position.y); - private void SetColor(ConsoleColor color, ConsoleColor background = ConsoleColor.Black) - { - Console.ForegroundColor = color; - Console.BackgroundColor = background; - } + private void SetColor(ConsoleColor color, ConsoleColor background = ConsoleColor.Black) + { + Console.ForegroundColor = color; + Console.BackgroundColor = background; + } - private void Move(int x, int y = 0) - { - _position = Math.Min(_buffer.Count, Math.Max(0, _position + x)); - _cursorLeft -= 1; //???? - } + private void Move(int x, int y = 0) + { + _position = Math.Min(_buffer.Count, Math.Max(0, _position + x)); + _cursorLeft -= 1; //???? + } - private void ClearLine() - { - int left = _cursorLeft; - while (_cursorLeft < Console.BufferWidth - 1) - Write(' '); - _cursorLeft = left; - } + private void ClearLine() + { + int left = _cursorLeft; + while (_cursorLeft < Console.BufferWidth - 1) + Write(' '); + _cursorLeft = left; + } - private void Print((int x, int y) origin, (int x, int y)? remain = null) - { - SetColor(ConsoleColor.White); - SetCursor(origin); - Write(" <: "); - foreach (var c in _buffer) { - if (c == '\n') { - ClearLine(); - Write("\n : "); - } else { - Write(c); + private void Print((int x, int y) origin, (int x, int y)? remain = null) + { + SetColor(ConsoleColor.White); + SetCursor(origin); + Write(" <: "); + foreach (var c in _buffer) { + if (c == '\n') { + ClearLine(); + Write("\n : "); + } else { + Write(c); + } + } + ClearLine(); + if (remain.HasValue) + SetCursor(remain.Value); + } + + private Stream Dispatch() + { + var stream = new MemoryStream(); + var data = _buffer.ToArray(); + stream.Write(_encoding.GetBytes(data)); + _history.Push(data); + _buffer.Clear(); + return stream; + } + + public ConsoleCode Read(out Stream? stream) + { + stream = null; + ConsoleKeyInfo input; + _origin = _cursorPosition; + _position = 0; + Print(_origin); + do { + if (UseSyntaxHighlighting) + new ConsoleRenderer(new MemoryStream(_encoding.GetBytes(_buffer.ToArray()))).Render(_origin); // ~ so efficient ~ XD + Print(_origin, _cursorPosition); + input = Console.ReadKey(true); + + if (input.Modifiers == ConsoleModifiers.Control) { + if (input.Key == ConsoleKey.C) + return ConsoleCode.Exit; + + if (input.Key == ConsoleKey.H) { + UseSyntaxHighlighting = !UseSyntaxHighlighting; + Write($"\n #: {nameof(UseSyntaxHighlighting)} = {UseSyntaxHighlighting}\n <: "); + _origin = _cursorPosition; } - } - ClearLine(); - if (remain.HasValue) - SetCursor(remain.Value); - } - - private Stream Dispatch() - { - var stream = new MemoryStream(); - var data = _buffer.ToArray(); - stream.Write(_encoding.GetBytes(data)); - _history.Push(data); - _buffer.Clear(); - return stream; - } - - public ConsoleCode Read(out Stream? stream) - { - stream = null; - ConsoleKeyInfo input; - _origin = _cursorPosition; - _position = 0; - Print(_origin); - do { - if (UseSyntaxHighlighting) - new ConsoleRenderer(new MemoryStream(_encoding.GetBytes(_buffer.ToArray()))).Render(_origin); // ~ so efficient ~ XD - Print(_origin, _cursorPosition); - input = Console.ReadKey(true); - - if (input.Modifiers == ConsoleModifiers.Control) { - if (input.Key == ConsoleKey.C) - return ConsoleCode.Exit; - - if (input.Key == ConsoleKey.H) { - UseSyntaxHighlighting = !UseSyntaxHighlighting; - Write($"\n #: {nameof(UseSyntaxHighlighting)} = {UseSyntaxHighlighting}\n <: "); - _origin = _cursorPosition; - } - if (input.Key == ConsoleKey.LeftArrow) { - - } - continue; - } - if (input.Key == ConsoleKey.LeftArrow) { - if (_position > 0) { - _position--; - _cursorLeft--; - } - continue; - } - if (input.Key == ConsoleKey.RightArrow) { - if (_position < _buffer.Count) { - _position++; - _cursorLeft++; - } - continue; } + continue; + } - if (input.Key == ConsoleKey.Backspace) { - if (_position > 0) { - _cursorLeft--; - _buffer.RemoveRange(--_position, 1); - } - continue; - } else if (input.Check(ConsoleKey.Enter, ConsoleModifiers.Shift)) { - _buffer.Insert(_position++, '\n'); - _cursorLeft = _cursorOffset; - _cursorTop++; - continue; - } else { - _buffer.Insert(_position++, input.KeyChar); - _cursorLeft++; + if (input.Key == ConsoleKey.LeftArrow) { + if (_position > 0) { + _position--; + _cursorLeft--; } - } while (!input.Check(ConsoleKey.Enter, ConsoleModifiers.None, true)); - stream = Dispatch(); - return ConsoleCode.OK; - } + continue; + } + + if (input.Key == ConsoleKey.RightArrow) { + if (_position < _buffer.Count) { + _position++; + _cursorLeft++; + } + continue; + } + + if (input.Key == ConsoleKey.Backspace) { + if (_position > 0) { + _cursorLeft--; + _buffer.RemoveRange(--_position, 1); + } + continue; + } else if (input.Check(ConsoleKey.Enter, ConsoleModifiers.Shift)) { + _buffer.Insert(_position++, '\n'); + _cursorLeft = _cursorOffset; + _cursorTop++; + continue; + } else { + _buffer.Insert(_position++, input.KeyChar); + _cursorLeft++; + } + } while (!input.Check(ConsoleKey.Enter, ConsoleModifiers.None, true)); + stream = Dispatch(); + return ConsoleCode.OK; + } } diff --git a/Qrakhen.Qamp.CLI/Program.cs b/Qrakhen.Qamp.CLI/Program.cs index 3768fbd..0187be7 100644 --- a/Qrakhen.Qamp.CLI/Program.cs +++ b/Qrakhen.Qamp.CLI/Program.cs @@ -47,123 +47,121 @@ bool useSyntaxHighlighting = false; ConsoleCode code = ConsoleCode.Error; Runner runner = new(new Options()); do { - Console.ForegroundColor = ConsoleColor.White; - MemoryStream stream = new MemoryStream(); - Console.Write(" <: "); - cursor = Console.GetCursorPosition(); - do { - if (useSyntaxHighlighting) - new ConsoleRenderer(stream).Render(cursor); - input = Console.ReadKey(true); + Console.ForegroundColor = ConsoleColor.White; + MemoryStream stream = new MemoryStream(); + Console.Write(" <: "); + cursor = Console.GetCursorPosition(); + do { + if (useSyntaxHighlighting) + new ConsoleRenderer(stream).Render(cursor); + input = Console.ReadKey(true); - if (input.Modifiers == ConsoleModifiers.Control) { - if (input.Key == ConsoleKey.H) { - useSyntaxHighlighting = !useSyntaxHighlighting; - Console.Write($"\n #: {nameof(useSyntaxHighlighting)} = {useSyntaxHighlighting}\n <: "); - cursor = Console.GetCursorPosition(); - } - if (input.Key == ConsoleKey.L) { - LoggerService.Default = LoggerService.Default < LogLevel.All ? LogLevel.All : LogLevel.Info; - Console.Write($"\n #: LogLevel = {LoggerService.Default}\n <: "); - cursor = Console.GetCursorPosition(); - } - continue; - } + if (input.Modifiers == ConsoleModifiers.Control) { + if (input.Key == ConsoleKey.H) { + useSyntaxHighlighting = !useSyntaxHighlighting; + Console.Write($"\n #: {nameof(useSyntaxHighlighting)} = {useSyntaxHighlighting}\n <: "); + cursor = Console.GetCursorPosition(); + } + if (input.Key == ConsoleKey.L) { + LoggerService.Default = LoggerService.Default < LogLevel.All ? LogLevel.All : LogLevel.Info; + Console.Write($"\n #: LogLevel = {LoggerService.Default}\n <: "); + cursor = Console.GetCursorPosition(); + } + continue; + } - if (input.Key == ConsoleKey.LeftArrow) { - if (stream.Position > 0) { - stream.Position--; - Console.CursorLeft--; - } - continue; - } + if (input.Key == ConsoleKey.LeftArrow) { + if (stream.Position > 0) { + stream.Position--; + Console.CursorLeft--; + } + continue; + } - if (input.Key == ConsoleKey.RightArrow) { - if (stream.Position < stream.Length) { - stream.Position++; - Console.CursorLeft++; - } - continue; - } + if (input.Key == ConsoleKey.RightArrow) { + if (stream.Position < stream.Length) { + stream.Position++; + Console.CursorLeft++; + } + continue; + } - if (input.Key == ConsoleKey.UpArrow) { - historyCursor = Math.Min(History.Count - 1, historyCursor + 1); - byte[] bytes = History[historyCursor]; - continue; - } + if (input.Key == ConsoleKey.UpArrow) { + historyCursor = Math.Min(History.Count - 1, historyCursor + 1); + byte[] bytes = History[historyCursor]; + continue; + } - if (input.Key == ConsoleKey.DownArrow) { - historyCursor = Math.Max(0, historyCursor - 1); - byte[] bytes = History[historyCursor]; - continue; - } + if (input.Key == ConsoleKey.DownArrow) { + historyCursor = Math.Max(0, historyCursor - 1); + byte[] bytes = History[historyCursor]; + continue; + } - if (input.Key == ConsoleKey.Backspace && stream.Position > 0) { + if (input.Key == ConsoleKey.Backspace && stream.Position > 0) { + Console.CursorLeft -= 1; + Console.Write(' '); + if (!useSyntaxHighlighting) Console.CursorLeft -= 1; - Console.Write(' '); - if (!useSyntaxHighlighting) - Console.CursorLeft -= 1; - //stream.Position--; - //stream.SetLength(stream.Position); - stream.Remove(stream.Position - 1, 1); - } else if (input.Key == ConsoleKey.Enter && input.Modifiers == ConsoleModifiers.Shift) { - if (!useSyntaxHighlighting) - Console.Write("\n : "); - stream.Insert(Encoding.Default.GetBytes(Environment.NewLine)); - } else if (Ignored.IndexOf(input.KeyChar) < 0) { - if (!useSyntaxHighlighting) - Console.Write(input.KeyChar); - stream.Insert(Encoding.Default.GetBytes([input.KeyChar], 0, 1)); - } - } while (input.Key != ConsoleKey.Enter || input.Modifiers == ConsoleModifiers.Shift); - try { - History.Insert(0, stream.GetBuffer()); - Console.WriteLine(); - runner.Run(stream); - stream.Dispose(); - } - catch (QampException e) { - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine($" !> {e.Message}"); - if (e.StackTrace != null) { - Console.Write($" ! "); - Console.WriteLine(string.Join("\n ! ", e.StackTrace.Split('\n'))); - } - } - catch (Exception e) { - Console.ForegroundColor = ConsoleColor.DarkRed; - Console.WriteLine($" !? {e.Message}"); - if (e.StackTrace != null) { - Console.Write($" ! "); - Console.WriteLine(string.Join("\n ! ", e.StackTrace.Split('\n'))); - } - } -} while(code != ConsoleCode.Exit); + //stream.Position--; + //stream.SetLength(stream.Position); + stream.Remove(stream.Position - 1, 1); + } else if (input.Key == ConsoleKey.Enter && input.Modifiers == ConsoleModifiers.Shift) { + if (!useSyntaxHighlighting) + Console.Write("\n : "); + stream.Insert(Encoding.Default.GetBytes(Environment.NewLine)); + } else if (Ignored.IndexOf(input.KeyChar) < 0) { + if (!useSyntaxHighlighting) + Console.Write(input.KeyChar); + stream.Insert(Encoding.Default.GetBytes([input.KeyChar], 0, 1)); + } + } while (input.Key != ConsoleKey.Enter || input.Modifiers == ConsoleModifiers.Shift); + try { + History.Insert(0, stream.GetBuffer()); + Console.WriteLine(); + runner.Run(stream); + stream.Dispose(); + } catch (QampException e) { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine($" !> {e.Message}"); + if (e.StackTrace != null) { + Console.Write($" ! "); + Console.WriteLine(string.Join("\n ! ", e.StackTrace.Split('\n'))); + } + } catch (Exception e) { + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine($" !? {e.Message}"); + if (e.StackTrace != null) { + Console.Write($" ! "); + Console.WriteLine(string.Join("\n ! ", e.StackTrace.Split('\n'))); + } + } +} while (code != ConsoleCode.Exit); public class Command { - public class Parameters - { + public class Parameters + { - } + } - public class Definition - { - public string Name { get; init; } - public string Alias { get; init; } + public class Definition + { + public string Name { get; init; } + public string Alias { get; init; } - public class Parameter - { - public string Name { get; init; } - public string Alias { get; init; } - } - } + public class Parameter + { + public string Name { get; init; } + public string Alias { get; init; } + } + } } public class ArgumentAttribute(string name, string alias, string description) { - public string Name { get; } = name; - public string Alias { get; } = alias; - public string Description { get; } = description; + public string Name { get; } = name; + public string Alias { get; } = alias; + public string Description { get; } = description; } \ No newline at end of file diff --git a/Qrakhen.Qamp.CLI/_Program.cs b/Qrakhen.Qamp.CLI/_Program.cs index 492ceb8..5be56ae 100644 --- a/Qrakhen.Qamp.CLI/_Program.cs +++ b/Qrakhen.Qamp.CLI/_Program.cs @@ -6,38 +6,38 @@ using System.Text; class C { - void X() - { - ConsoleCode code = ConsoleCode.Exit; - Runner runner = new Runner(new Options()); - ConsoleWriter cli = new ConsoleWriter(Encoding.Default); - do { - try { - code = cli.Read(out Stream? stream); - if (code == ConsoleCode.OK) { - if (stream == null) - throw new QampException($"Stream from CLI was null {code}"); - Console.WriteLine(); - runner.Run(stream); - } - if (code == ConsoleCode.Error) - throw new QampException($"CLI returned {code}"); - - } catch (QampException e) { - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine($" !> {e.Message}"); - if (e.StackTrace != null) { - Console.Write($" ! "); - Console.WriteLine(string.Join("\n ! ", e.StackTrace.Split('\n'))); - } - } catch (Exception e) { - Console.ForegroundColor = ConsoleColor.DarkRed; - Console.WriteLine($" !? {e.Message}"); - if (e.StackTrace != null) { - Console.Write($" ! "); - Console.WriteLine(string.Join("\n ! ", e.StackTrace.Split('\n'))); - } + void X() + { + ConsoleCode code = ConsoleCode.Exit; + Runner runner = new Runner(new Options()); + ConsoleWriter cli = new ConsoleWriter(Encoding.Default); + do { + try { + code = cli.Read(out Stream? stream); + if (code == ConsoleCode.OK) { + if (stream == null) + throw new QampException($"Stream from CLI was null {code}"); + Console.WriteLine(); + runner.Run(stream); } - } while (code != ConsoleCode.Exit); - } + if (code == ConsoleCode.Error) + throw new QampException($"CLI returned {code}"); + + } catch (QampException e) { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine($" !> {e.Message}"); + if (e.StackTrace != null) { + Console.Write($" ! "); + Console.WriteLine(string.Join("\n ! ", e.StackTrace.Split('\n'))); + } + } catch (Exception e) { + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine($" !? {e.Message}"); + if (e.StackTrace != null) { + Console.Write($" ! "); + Console.WriteLine(string.Join("\n ! ", e.StackTrace.Split('\n'))); + } + } + } while (code != ConsoleCode.Exit); + } } diff --git a/Qrakhen.Qamp.Core.Tests/UnitTest1.cs b/Qrakhen.Qamp.Core.Tests/UnitTest1.cs index 3011053..cd49e0d 100644 --- a/Qrakhen.Qamp.Core.Tests/UnitTest1.cs +++ b/Qrakhen.Qamp.Core.Tests/UnitTest1.cs @@ -2,9 +2,9 @@ public class UnitTest1 { - [Fact] - public void Test1() - { + [Fact] + public void Test1() + { - } + } } diff --git a/Qrakhen.Qamp.Core/Abstractions/IDebug.cs b/Qrakhen.Qamp.Core/Abstractions/IDebug.cs index 7648ccf..711216c 100644 --- a/Qrakhen.Qamp.Core/Abstractions/IDebug.cs +++ b/Qrakhen.Qamp.Core/Abstractions/IDebug.cs @@ -4,26 +4,26 @@ namespace Qrakhen.Qamp.Core.Abstractions; public interface IDebug { - T Debug(DebugLevel level = DebugLevel.None); + T Debug(DebugLevel level = DebugLevel.None); } public interface IDebug { - TOut Debug(TContext? context, DebugLevel level = DebugLevel.None); + TOut Debug(TContext? context, DebugLevel level = DebugLevel.None); } public enum DebugLevel { - None = 0, - Mild = 1, - Strong = 2, - Verbose = 3 + None = 0, + Mild = 1, + Strong = 2, + Verbose = 3 } public static class Debugger { - public static string GetContextString(object? origin, [CallerMemberName] string? caller = null) - { - return $"{{Debugger::Builder}}: [{origin?.ToString() ?? "null"}] <{origin?.GetType().Name ?? "null"}> ({caller ?? "null"})"; - } + public static string GetContextString(object? origin, [CallerMemberName] string? caller = null) + { + return $"{{Debugger::Builder}}: [{origin?.ToString() ?? "null"}] <{origin?.GetType().Name ?? "null"}> ({caller ?? "null"})"; + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Abstractions/ISerialize.cs b/Qrakhen.Qamp.Core/Abstractions/ISerialize.cs index 0df2445..67ca8a1 100644 --- a/Qrakhen.Qamp.Core/Abstractions/ISerialize.cs +++ b/Qrakhen.Qamp.Core/Abstractions/ISerialize.cs @@ -2,6 +2,6 @@ public interface ISerialize { - byte[] Serialize(); - static abstract TSelf Deserialize(byte[] data); + byte[] Serialize(); + static abstract TSelf Deserialize(byte[] data); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Assert.cs b/Qrakhen.Qamp.Core/Assert.cs index 16bbe72..b4c5c83 100644 --- a/Qrakhen.Qamp.Core/Assert.cs +++ b/Qrakhen.Qamp.Core/Assert.cs @@ -7,49 +7,49 @@ namespace Qrakhen.Qamp.Core; public static class Assert { - public static void IsPrimitive(params Value[] values) - { - AssertAndThrow(() => values.All(value => value.Is(V.Primitive, false)), values); - } + public static void IsPrimitive(params Value[] values) + { + AssertAndThrow(() => values.All(value => value.Is(V.Primitive, false)), values); + } - public static void NotZero(params Value[] values) - { - AssertAndThrow(() => values.All(value => value.Signed != 0), values); - } + public static void NotZero(params Value[] values) + { + AssertAndThrow(() => values.All(value => value.Signed != 0), values); + } - public static void IsInteger(params Value[] values) - { - AssertAndThrow(() => values.All(value => value.Is(V.Integer, false)), values); - } + public static void IsInteger(params Value[] values) + { + AssertAndThrow(() => values.All(value => value.Is(V.Integer, false)), values); + } - public static void NotVoid(params Value[] values) - { - AssertAndThrow(() => values.All(value => value.Type != V.Void), values); - } + public static void NotVoid(params Value[] values) + { + AssertAndThrow(() => values.All(value => value.Type != V.Void), values); + } - private static void AssertAndThrow(Func assertion, object? parameter, [CallerMemberName] string? method = "") => - AssertAndThrow(assertion, [parameter], method); + private static void AssertAndThrow(Func assertion, object? parameter, [CallerMemberName] string? method = "") => + AssertAndThrow(assertion, [parameter], method); - private static void AssertAndThrow( - Func assertion, - object?[] parameters, - [CallerMemberName] string? method = "") - { - if (!assertion.Invoke()) - throw new AssertionException(method ?? "", parameters); - } + private static void AssertAndThrow( + Func assertion, + object?[] parameters, + [CallerMemberName] string? method = "") + { + if (!assertion.Invoke()) + throw new AssertionException(method ?? "", parameters); + } - public class AssertionException : Exception - { - public readonly string Assertion; - public readonly object?[] Parameters; + public class AssertionException : Exception + { + public readonly string Assertion; + public readonly object?[] Parameters; - public AssertionException(string assertion, params object?[] parameters) - : base($"Assertion {assertion} failed for parameters:{Environment.NewLine}" + - $"{string.Join(Environment.NewLine, parameters.Select(p => $" - <{p?.GetType().Name ?? "null"}>{p?.ToString() ?? "null"}"))}") - { - Assertion = assertion; - Parameters = parameters; - } - } + public AssertionException(string assertion, params object?[] parameters) + : base($"Assertion {assertion} failed for parameters:{Environment.NewLine}" + + $"{string.Join(Environment.NewLine, parameters.Select(p => $" - <{p?.GetType().Name ?? "null"}>{p?.ToString() ?? "null"}"))}") + { + Assertion = assertion; + Parameters = parameters; + } + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Benchmark.cs b/Qrakhen.Qamp.Core/Benchmark.cs index fd98708..b7df3ed 100644 --- a/Qrakhen.Qamp.Core/Benchmark.cs +++ b/Qrakhen.Qamp.Core/Benchmark.cs @@ -6,88 +6,86 @@ namespace Qrakhen.Qamp.Core; public static class Benchmark { - private static readonly Dictionary _clocks = new(); + private static readonly Dictionary _clocks = new(); - public static bool Active { get; set; } + public static bool Active { get; set; } - private static readonly ILogger _logger = LoggerService.Get(nameof(Benchmark)); + private static readonly ILogger _logger = LoggerService.Get(nameof(Benchmark)); - private static string MakeKey(string? id, string? member, string? file) - { - if (member == null) - return "global"; - return $"{file?.Split('\\').Last() ?? "unknown"}{(id == null ? "" : $"<{id}>")}::{member}"; - } + private static string MakeKey(string? id, string? member, string? file) + { + if (member == null) + return "global"; + return $"{file?.Split('\\').Last() ?? "unknown"}{(id == null ? "" : $"<{id}>")}::{member}"; + } - public static void Start( - string? message = null, - string? id = null, - [CallerMemberName] string? member = null, - [CallerFilePath] string? file = null, - [CallerLineNumber] int? line = null) - { - if (!Active) - return; + public static void Start( + string? message = null, + string? id = null, + [CallerMemberName] string? member = null, + [CallerFilePath] string? file = null, + [CallerLineNumber] int? line = null) + { + if (!Active) + return; - string key = MakeKey(id, member, file); + string key = MakeKey(id, member, file); - if (!_clocks.TryGetValue(key, out Stopwatch? sw)) - { - sw = _clocks[key] = new Stopwatch(); - Console.WriteLine($" ::: Registered new benchmark clock '{key}'"); - } + if (!_clocks.TryGetValue(key, out Stopwatch? sw)) { + sw = _clocks[key] = new Stopwatch(); + Console.WriteLine($" ::: Registered new benchmark clock '{key}'"); + } - if (!string.IsNullOrEmpty(message)) - Console.WriteLine($" ::: {key}:{line} > {message}"); + if (!string.IsNullOrEmpty(message)) + Console.WriteLine($" ::: {key}:{line} > {message}"); - if (sw.IsRunning) - Console.WriteLine($" ::: {key}:{line} > already running with an elapsed time of {sw.Elapsed}. clock was reset."); + if (sw.IsRunning) + Console.WriteLine($" ::: {key}:{line} > already running with an elapsed time of {sw.Elapsed}. clock was reset."); - sw.Reset(); - sw.Start(); - } + sw.Reset(); + sw.Start(); + } - public static long Report( - string? message = null, - string? id = null, - bool keep = true, - [CallerMemberName] string? member = null, - [CallerFilePath] string? file = null, - [CallerLineNumber] int? line = null) - { - if (!Active) - return 0; + public static long Report( + string? message = null, + string? id = null, + bool keep = true, + [CallerMemberName] string? member = null, + [CallerFilePath] string? file = null, + [CallerLineNumber] int? line = null) + { + if (!Active) + return 0; - string key = MakeKey(id, member, file); + string key = MakeKey(id, member, file); - if (!_clocks.TryGetValue(key, out Stopwatch sw)) - { + if (!_clocks.TryGetValue(key, out Stopwatch sw)) { #if LOG _logger.Debug($"No clock found for '{key}', start one first using Benchmark.Start()"); #endif - return 0; - } + return 0; + } - sw.Stop(); + sw.Stop(); #if LOG _logger.Debug($" ::: {key}:{line} > {message ?? "Elapsed"}: {sw.Elapsed}"); #endif - if (keep) - sw.Start(); + if (keep) + sw.Start(); - return sw.ElapsedMilliseconds; - } + return sw.ElapsedMilliseconds; + } - public static long End( - string? message = null, - string? id = null, - [CallerMemberName] string? member = null, - [CallerFilePath] string? file = null, - [CallerLineNumber] int? line = null) - { - if (!Active) - return 0; + public static long End( + string? message = null, + string? id = null, + [CallerMemberName] string? member = null, + [CallerFilePath] string? file = null, + [CallerLineNumber] int? line = null) + { + if (!Active) + return 0; - return Report(message, id, false, member, file, line); - } + return Report(message, id, false, member, file, line); + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Collections/Abstractions/IAdd.cs b/Qrakhen.Qamp.Core/Collections/Abstractions/IAdd.cs index a822d13..c244dbb 100644 --- a/Qrakhen.Qamp.Core/Collections/Abstractions/IAdd.cs +++ b/Qrakhen.Qamp.Core/Collections/Abstractions/IAdd.cs @@ -4,5 +4,5 @@ namespace Qrakhen.Qamp.Core.Collections.Abstractions; public interface IAdd { - TKey Add(TValue value); + TKey Add(TValue value); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Collections/Abstractions/ICapturableBuffer.cs b/Qrakhen.Qamp.Core/Collections/Abstractions/ICapturableBuffer.cs index 919e290..6bacffc 100644 --- a/Qrakhen.Qamp.Core/Collections/Abstractions/ICapturableBuffer.cs +++ b/Qrakhen.Qamp.Core/Collections/Abstractions/ICapturableBuffer.cs @@ -2,7 +2,7 @@ public interface ICaptureBuffer { - THandle BeginCapture(); - TData[] EndCapture(THandle handle); - int Captured(THandle handle); + THandle BeginCapture(); + TData[] EndCapture(THandle handle); + int Captured(THandle handle); } diff --git a/Qrakhen.Qamp.Core/Collections/Abstractions/IConsumable.cs b/Qrakhen.Qamp.Core/Collections/Abstractions/IConsumable.cs index d8e3acd..1855c0b 100644 --- a/Qrakhen.Qamp.Core/Collections/Abstractions/IConsumable.cs +++ b/Qrakhen.Qamp.Core/Collections/Abstractions/IConsumable.cs @@ -2,5 +2,5 @@ public interface IConsumable { - void Consume(T expected, string? message = null); + void Consume(T expected, string? message = null); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Collections/Abstractions/IGet.cs b/Qrakhen.Qamp.Core/Collections/Abstractions/IGet.cs index 5045217..f2f15c7 100644 --- a/Qrakhen.Qamp.Core/Collections/Abstractions/IGet.cs +++ b/Qrakhen.Qamp.Core/Collections/Abstractions/IGet.cs @@ -2,5 +2,5 @@ public interface IGet { - TValue Get(TKey index); + TValue Get(TKey index); } diff --git a/Qrakhen.Qamp.Core/Collections/Abstractions/IPeekable.cs b/Qrakhen.Qamp.Core/Collections/Abstractions/IPeekable.cs index 9b36dab..eec5d08 100644 --- a/Qrakhen.Qamp.Core/Collections/Abstractions/IPeekable.cs +++ b/Qrakhen.Qamp.Core/Collections/Abstractions/IPeekable.cs @@ -2,5 +2,5 @@ public interface IPeekable { - T Peek(int delta = -1); + T Peek(int delta = -1); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Collections/Abstractions/IReadable.cs b/Qrakhen.Qamp.Core/Collections/Abstractions/IReadable.cs index 1747bb1..3f842c1 100644 --- a/Qrakhen.Qamp.Core/Collections/Abstractions/IReadable.cs +++ b/Qrakhen.Qamp.Core/Collections/Abstractions/IReadable.cs @@ -2,6 +2,6 @@ public interface IReadable { - T Read(int position); - T[] Read(int position, int length); + T Read(int position); + T[] Read(int position, int length); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Collections/Abstractions/IReader.cs b/Qrakhen.Qamp.Core/Collections/Abstractions/IReader.cs index 1e0c2d0..df9bba7 100644 --- a/Qrakhen.Qamp.Core/Collections/Abstractions/IReader.cs +++ b/Qrakhen.Qamp.Core/Collections/Abstractions/IReader.cs @@ -4,7 +4,7 @@ namespace Qrakhen.Qamp.Core.Collections.Abstractions; public interface IReader { - TokenPosition CurrentPosition { get; } - bool Done { get; } - T NextToken(bool includeCompilationIrrelevant = false); + TokenPosition CurrentPosition { get; } + bool Done { get; } + T NextToken(bool includeCompilationIrrelevant = false); } diff --git a/Qrakhen.Qamp.Core/Collections/Abstractions/ISeekable.cs b/Qrakhen.Qamp.Core/Collections/Abstractions/ISeekable.cs index ccebc5b..f5400a0 100644 --- a/Qrakhen.Qamp.Core/Collections/Abstractions/ISeekable.cs +++ b/Qrakhen.Qamp.Core/Collections/Abstractions/ISeekable.cs @@ -2,6 +2,6 @@ public interface ISeekable { - TKey Position { get; } - TValue Seek(TKey position); + TKey Position { get; } + TValue Seek(TKey position); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Collections/Abstractions/ISet.cs b/Qrakhen.Qamp.Core/Collections/Abstractions/ISet.cs index 7c2b244..c3e6719 100644 --- a/Qrakhen.Qamp.Core/Collections/Abstractions/ISet.cs +++ b/Qrakhen.Qamp.Core/Collections/Abstractions/ISet.cs @@ -2,7 +2,7 @@ public interface ISet { - TValue this[TKey index] { set; } + TValue this[TKey index] { set; } - void Set(TKey index, TValue value); + void Set(TKey index, TValue value); } diff --git a/Qrakhen.Qamp.Core/Collections/Abstractions/IStack.cs b/Qrakhen.Qamp.Core/Collections/Abstractions/IStack.cs index 8463e8f..b22557e 100644 --- a/Qrakhen.Qamp.Core/Collections/Abstractions/IStack.cs +++ b/Qrakhen.Qamp.Core/Collections/Abstractions/IStack.cs @@ -4,10 +4,10 @@ public interface IStack : IPush, IPop; public interface IPush { - TKey Push(T value); + TKey Push(T value); } public interface IPop { - T Pop(); + T Pop(); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Collections/Abstractions/ISteppable.cs b/Qrakhen.Qamp.Core/Collections/Abstractions/ISteppable.cs index 7f7fab9..e20ba7f 100644 --- a/Qrakhen.Qamp.Core/Collections/Abstractions/ISteppable.cs +++ b/Qrakhen.Qamp.Core/Collections/Abstractions/ISteppable.cs @@ -2,6 +2,6 @@ public interface ISteppable { - bool Done { get; } - T Next(); + bool Done { get; } + T Next(); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Collections/Abstractions/IToArray.cs b/Qrakhen.Qamp.Core/Collections/Abstractions/IToArray.cs index dc032e8..f80502c 100644 --- a/Qrakhen.Qamp.Core/Collections/Abstractions/IToArray.cs +++ b/Qrakhen.Qamp.Core/Collections/Abstractions/IToArray.cs @@ -2,5 +2,5 @@ public interface IToArray { - T[] ToArray(); + T[] ToArray(); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Collections/Expander.cs b/Qrakhen.Qamp.Core/Collections/Expander.cs index 9efa56f..b1f31f4 100644 --- a/Qrakhen.Qamp.Core/Collections/Expander.cs +++ b/Qrakhen.Qamp.Core/Collections/Expander.cs @@ -11,63 +11,63 @@ namespace Qrakhen.Qamp.Core.Collections; /// and we don't need that here in Q&. /// /// -public abstract class Expander : +public abstract class Expander : IEnumerable, IGetSet, IAdd { - protected T[] Data; + protected T[] Data; - public long Count { get; protected set; } = 0; - public long Capacity => Data.Length; - - protected Expander(int capacity = 0x10) - { - Data = new T[capacity]; - } + public long Count { get; protected set; } = 0; + public long Capacity => Data.Length; - protected Expander(IEnumerable data) - { - Data = data.ToArray(); - Count = Data.Length; - } + protected Expander(int capacity = 0x10) + { + Data = new T[capacity]; + } - public T this[long index] { - get => Get(index); - set => Set(index, value); - } + protected Expander(IEnumerable data) + { + Data = data.ToArray(); + Count = Data.Length; + } - public T Get(long index) => Data[index]; + public T this[long index] { + get => Get(index); + set => Set(index, value); + } - public void Set(long index, T value) - { - Prepare(index); - Data[index] = value; - } + public T Get(long index) => Data[index]; - public long Add(T value) - { - Prepare(Count); - Data[Count] = value; - return Count++; - } + public void Set(long index, T value) + { + Prepare(index); + Data[index] = value; + } - protected void Prepare(long position) - { - while (position >= Data.Length) { - T[] grown = new T[Data.Length * 2]; - Array.Copy(Data, grown, Count); - Data = grown; - } - } + public long Add(T value) + { + Prepare(Count); + Data[Count] = value; + return Count++; + } - public IEnumerator GetEnumerator() - { - foreach (T? item in Data) { - yield return item; - } - } + protected void Prepare(long position) + { + while (position >= Data.Length) { + T[] grown = new T[Data.Length * 2]; + Array.Copy(Data, grown, Count); + Data = grown; + } + } - IEnumerator IEnumerable.GetEnumerator() - => GetEnumerator(); + public IEnumerator GetEnumerator() + { + foreach (T? item in Data) { + yield return item; + } + } + + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); } diff --git a/Qrakhen.Qamp.Core/Collections/FixedArray.cs b/Qrakhen.Qamp.Core/Collections/FixedArray.cs index ceeea77..da02eaf 100644 --- a/Qrakhen.Qamp.Core/Collections/FixedArray.cs +++ b/Qrakhen.Qamp.Core/Collections/FixedArray.cs @@ -9,33 +9,33 @@ namespace Qrakhen.Qamp.Core.Collections; /// public class FixedArray : IEnumerable, IGetSet { - protected T[] Data; + protected T[] Data; - public long Length => Data.LongLength; + public long Length => Data.LongLength; - public T this[long index] { - get => Get(index); - set => Set(index, value); - } + public T this[long index] { + get => Get(index); + set => Set(index, value); + } - public FixedArray(IEnumerable data) - { - Data = data.ToArray(); - } + public FixedArray(IEnumerable data) + { + Data = data.ToArray(); + } - public T Get(long index) => Data[index]; + public T Get(long index) => Data[index]; - public void Set(long index, T value) - { - Data[index] = value; - } + public void Set(long index, T value) + { + Data[index] = value; + } - public IEnumerator GetEnumerator() - { - foreach (var item in Data) - yield return item; - } + public IEnumerator GetEnumerator() + { + foreach (var item in Data) + yield return item; + } - IEnumerator IEnumerable.GetEnumerator() - => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); } diff --git a/Qrakhen.Qamp.Core/Collections/Pointer.cs b/Qrakhen.Qamp.Core/Collections/Pointer.cs index bedf011..a1c7232 100644 --- a/Qrakhen.Qamp.Core/Collections/Pointer.cs +++ b/Qrakhen.Qamp.Core/Collections/Pointer.cs @@ -7,52 +7,52 @@ namespace Qrakhen.Qamp.Core.Collections; /// public class Pointer { - protected IGetSet Target; - public long Cursor; + protected IGetSet Target; + public long Cursor; - public T Current { - get => Get(); - set => Set(value); - } + public T Current { + get => Get(); + set => Set(value); + } - public Pointer(IGetSet target, long pointer = 0) - { - Target = target; - Cursor = pointer; - } + public Pointer(IGetSet target, long pointer = 0) + { + Target = target; + Cursor = pointer; + } - public Pointer Branch(long delta = 0) - { - return new Pointer(Target, Cursor + delta); - } + public Pointer Branch(long delta = 0) + { + return new Pointer(Target, Cursor + delta); + } - /// - /// Returns the next item from and increases the pointer by 1. - /// - public T Next() => Target.Get(Cursor++); + /// + /// Returns the next item from and increases the pointer by 1. + /// + public T Next() => Target.Get(Cursor++); - /// - /// Sets the value of RELATIVE from the current position (). - /// - public void Set(long delta, T value) => Target.Set(Cursor + delta, value); + /// + /// Sets the value of RELATIVE from the current position (). + /// + public void Set(long delta, T value) => Target.Set(Cursor + delta, value); - /// - /// Sets the value of at the current location. - /// - public void Set(T value) => Set(Cursor, value); + /// + /// Sets the value of at the current location. + /// + public void Set(T value) => Set(Cursor, value); - /// - /// Gets the value of RELATIVE from the current position (). - /// - public T Get(long delta) => Target.Get(Cursor + delta); + /// + /// Gets the value of RELATIVE from the current position (). + /// + public T Get(long delta) => Target.Get(Cursor + delta); - /// - /// Gets the value of at the current location. - /// - public T Get() => Get(Cursor); + /// + /// Gets the value of at the current location. + /// + public T Get() => Get(Cursor); - public override string ToString() - { - return $"&{Cursor:X4}={Current}"; - } + public override string ToString() + { + return $"&{Cursor:X4}={Current}"; + } } diff --git a/Qrakhen.Qamp.Core/Collections/PopStack.cs b/Qrakhen.Qamp.Core/Collections/PopStack.cs index 0734330..804882b 100644 --- a/Qrakhen.Qamp.Core/Collections/PopStack.cs +++ b/Qrakhen.Qamp.Core/Collections/PopStack.cs @@ -6,38 +6,38 @@ namespace Qrakhen.Qamp.Core.Collections; /// /// Pop-Only stack with a fixed array that is gradually reduced. /// -public class PopStack : +public class PopStack : IEnumerable, IPop, IPeekable { - private readonly T[] _data; + private readonly T[] _data; - private int _position; + private int _position; - public int Position => _position; - public int Length => _data.Length; - public bool Done => _position >= _data.Length; + public int Position => _position; + public int Length => _data.Length; + public bool Done => _position >= _data.Length; - public PopStack(IEnumerable data) - { - _data = data.ToArray(); - _position = 0; - } + public PopStack(IEnumerable data) + { + _data = data.ToArray(); + _position = 0; + } - public T Pop() => _data[_position++]; + public T Pop() => _data[_position++]; - public T Peek(int delta = 0) => _data[_position + delta]; + public T Peek(int delta = 0) => _data[_position + delta]; - public bool CanPeek(int delta = 0) - => _position + delta > -1 && _position + delta < _data.Length; + public bool CanPeek(int delta = 0) + => _position + delta > -1 && _position + delta < _data.Length; - public IEnumerator GetEnumerator() - { - foreach (var item in _data) - yield return item; - } + public IEnumerator GetEnumerator() + { + foreach (var item in _data) + yield return item; + } - IEnumerator IEnumerable.GetEnumerator() - => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); } diff --git a/Qrakhen.Qamp.Core/Collections/PushStack.cs b/Qrakhen.Qamp.Core/Collections/PushStack.cs index 2298f32..b35d99a 100644 --- a/Qrakhen.Qamp.Core/Collections/PushStack.cs +++ b/Qrakhen.Qamp.Core/Collections/PushStack.cs @@ -6,55 +6,55 @@ namespace Qrakhen.Qamp.Core.Collections; /// Push-only Stack that is based on . /// /// -public class PushStack : - Expander, +public class PushStack : + Expander, IPush, IToArray { - public PushStack(int initialCapacity = 0x10) - { - Data = new T[initialCapacity]; - } + public PushStack(int initialCapacity = 0x10) + { + Data = new T[initialCapacity]; + } - public T? Find(Func callback) - { - for (int i = 0; i < Count; i++) - if (callback(Data[i])) - return Data[i]; - return default; - } + public T? Find(Func callback) + { + for (int i = 0; i < Count; i++) + if (callback(Data[i])) + return Data[i]; + return default; + } - public void Push(T[] array) - { - foreach (T value in array) { - Add(value); - } - } + public void Push(T[] array) + { + foreach (T value in array) { + Add(value); + } + } - public void Push(IEnumerable array) - { - foreach (T value in array) { - Add(value); - } - } + public void Push(IEnumerable array) + { + foreach (T value in array) { + Add(value); + } + } - public long Push(T value) => Add(value); + public long Push(T value) => Add(value); - public bool TryGet(long index, out T value) - { - value = default; - if (index < 0 || index >= Count) - return false; - value = Data[index]; - return true; - } + public bool TryGet(long index, out T value) + { + value = default; + if (index < 0 || index >= Count) + return false; + value = Data[index]; + return true; + } - public T[] ToArray() => Data.Subset(0, Count); + public T[] ToArray() => Data.Subset(0, Count); - public T[] Subset(long from, int length) - { - T[] result = new T[length]; - Array.Copy(Data, from, result, 0, length); - return result; - } + public T[] Subset(long from, int length) + { + T[] result = new T[length]; + Array.Copy(Data, from, result, 0, length); + return result; + } } diff --git a/Qrakhen.Qamp.Core/Collections/Register.cs b/Qrakhen.Qamp.Core/Collections/Register.cs index 3796c30..4ea8c43 100644 --- a/Qrakhen.Qamp.Core/Collections/Register.cs +++ b/Qrakhen.Qamp.Core/Collections/Register.cs @@ -7,42 +7,42 @@ namespace Qrakhen.Qamp.Core.Collections; /// /// Dictionary wrapper implementing . /// -public class Register : +public class Register : IGetSet, IToArray, IEnumerable> where TKey : notnull { - private readonly Dictionary _data = new(); + private readonly Dictionary _data = new(); - public int Length => _data.Count; + public int Length => _data.Count; - public TValue this[TKey key] { - get => Get(key); - set => Set(key, value); - } + public TValue this[TKey key] { + get => Get(key); + set => Set(key, value); + } - public TKey Add(TKey key, TValue value) - { - _data.Add(key, value); - return key; - } + public TKey Add(TKey key, TValue value) + { + _data.Add(key, value); + return key; + } - public bool TryGet(TKey key, [MaybeNullWhen(false)] out TValue value) => _data.TryGetValue(key, out value); - public TValue Get(TKey key) => _data[key]; - public void Set(TKey key, TValue value) => _data[key] = value; - public bool Has(TKey key) => _data.ContainsKey(key); + public bool TryGet(TKey key, [MaybeNullWhen(false)] out TValue value) => _data.TryGetValue(key, out value); + public TValue Get(TKey key) => _data[key]; + public void Set(TKey key, TValue value) => _data[key] = value; + public bool Has(TKey key) => _data.ContainsKey(key); - public TValue[] ToArray() => _data.Values.ToArray(); + public TValue[] ToArray() => _data.Values.ToArray(); - public IEnumerator> GetEnumerator() - { - foreach (var item in _data) - yield return item; - } + public IEnumerator> GetEnumerator() + { + foreach (var item in _data) + yield return item; + } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } } diff --git a/Qrakhen.Qamp.Core/Collections/StackLike.cs b/Qrakhen.Qamp.Core/Collections/StackLike.cs index 4524a97..b5c4a57 100644 --- a/Qrakhen.Qamp.Core/Collections/StackLike.cs +++ b/Qrakhen.Qamp.Core/Collections/StackLike.cs @@ -13,47 +13,47 @@ public class StackLike : Expander, IPeekable, IToArray { - public long Position => Count; + public long Position => Count; - public T this[int position] { - get => Data[position]; - set => Data[position] = value; - } + public T this[int position] { + get => Data[position]; + set => Data[position] = value; + } - public StackLike(int capacity = 0x10) - { - Data = new T[capacity]; - Count = 0; - } + public StackLike(int capacity = 0x10) + { + Data = new T[capacity]; + Count = 0; + } - public StackLike(IEnumerable data) - { - Data = data.ToArray(); - Count = 0; - } + public StackLike(IEnumerable data) + { + Data = data.ToArray(); + Count = 0; + } - public long Push(T value) => Add(value); + public long Push(T value) => Add(value); - public T Pop() => Data[--Count]; + public T Pop() => Data[--Count]; - public T Seek(long position) - { - Count = position; - return this[Count]; - } + public T Seek(long position) + { + Count = position; + return this[Count]; + } - public T Peek(int delta = -1) => Data[Count + delta]; + public T Peek(int delta = -1) => Data[Count + delta]; - public bool CanPeek(int delta = 0) - => Count + delta > -1 && Count + delta < Count; + public bool CanPeek(int delta = 0) + => Count + delta > -1 && Count + delta < Count; - /// - /// Decimates this stack down to the given position, overwriting everything beyond that when pushing in the future. - /// - public void Decimate(long position) - { - Count = position; - } + /// + /// Decimates this stack down to the given position, overwriting everything beyond that when pushing in the future. + /// + public void Decimate(long position) + { + Count = position; + } - public T[] ToArray() => Data.ToArray(); + public T[] ToArray() => Data.ToArray(); } diff --git a/Qrakhen.Qamp.Core/Compilation/Builders/Builder.cs b/Qrakhen.Qamp.Core/Compilation/Builders/Builder.cs index b54d7df..14ac499 100644 --- a/Qrakhen.Qamp.Core/Compilation/Builders/Builder.cs +++ b/Qrakhen.Qamp.Core/Compilation/Builders/Builder.cs @@ -4,17 +4,17 @@ namespace Qrakhen.Qamp.Core.Compilation.Builders; public class Builder { - public Builder? Outer { get; init; } - public FunctionBuilder Function = new(); - public readonly FunctionType Type; + public Builder? Outer { get; init; } + public FunctionBuilder Function = new(); + public readonly FunctionType Type; - public StackLike Locals = []; - public StackLike Outers = []; - public int ScopeDepth = 0; + public StackLike Locals = []; + public StackLike Outers = []; + public int ScopeDepth = 0; - public Builder(FunctionType type = FunctionType.Code, Builder? outer = null) - { - Type = type; - Outer = outer; - } + public Builder(FunctionType type = FunctionType.Code, Builder? outer = null) + { + Type = type; + Outer = outer; + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Compilation/Builders/ClassBuilder.cs b/Qrakhen.Qamp.Core/Compilation/Builders/ClassBuilder.cs index 5a163d4..048802c 100644 --- a/Qrakhen.Qamp.Core/Compilation/Builders/ClassBuilder.cs +++ b/Qrakhen.Qamp.Core/Compilation/Builders/ClassBuilder.cs @@ -2,8 +2,8 @@ public class ClassBuilder { - public string Name; + public string Name; - public ClassBuilder? Outer; - public bool IsDerived; + public ClassBuilder? Outer; + public bool IsDerived; } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Compilation/Builders/FunctionBuilder.cs b/Qrakhen.Qamp.Core/Compilation/Builders/FunctionBuilder.cs index e5cbfa5..07ed157 100644 --- a/Qrakhen.Qamp.Core/Compilation/Builders/FunctionBuilder.cs +++ b/Qrakhen.Qamp.Core/Compilation/Builders/FunctionBuilder.cs @@ -4,15 +4,15 @@ namespace Qrakhen.Qamp.Core.Compilation.Builders; public class FunctionBuilder { - public SegmentBuilder Segment = new(); - public string Name; - public int OuterCount; - public int ArgumentCount; + public SegmentBuilder Segment = new(); + public string Name; + public int OuterCount; + public int ArgumentCount; - public long CurrentInstruction => Segment.Instructions.Count; + public long CurrentInstruction => Segment.Instructions.Count; - public Function Build() - { - return new Function(Name, Segment.Build(), OuterCount, ArgumentCount); - } + public Function Build() + { + return new Function(Name, Segment.Build(), OuterCount, ArgumentCount); + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Compilation/Builders/IBuilder.cs b/Qrakhen.Qamp.Core/Compilation/Builders/IBuilder.cs index f0233d6..ad9f4e5 100644 --- a/Qrakhen.Qamp.Core/Compilation/Builders/IBuilder.cs +++ b/Qrakhen.Qamp.Core/Compilation/Builders/IBuilder.cs @@ -2,5 +2,5 @@ public interface IBuilder { - public TOut Build(); + public TOut Build(); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Compilation/Builders/SegmentBuilder.cs b/Qrakhen.Qamp.Core/Compilation/Builders/SegmentBuilder.cs index 51c9632..e70f7d6 100644 --- a/Qrakhen.Qamp.Core/Compilation/Builders/SegmentBuilder.cs +++ b/Qrakhen.Qamp.Core/Compilation/Builders/SegmentBuilder.cs @@ -7,34 +7,33 @@ namespace Qrakhen.Qamp.Core.Compilation.Builders; public class SegmentBuilder() : IBuilder, IDebug { - public readonly PushStack Instructions = new(); - public readonly PushStack Constants = new(); + public readonly PushStack Instructions = new(); + public readonly PushStack Constants = new(); - public Segment Build() - { - return new Segment(Instructions.ToArray(), Constants.ToArray()); - } + public Segment Build() + { + return new Segment(Instructions.ToArray(), Constants.ToArray()); + } - public string Debug(DebugLevel level = DebugLevel.None) - { - string str = Debugger.GetContextString(this); - for (int i = 0; i < Instructions.Count; i++) - { - var instruction = Instructions[i]; - /*if ((instruction.Code & 0x80) == 1) { - // dynamic - int length = instruction.Code & (0x80 - 1); - byte[] index = Instructions.Subset(i + 1, length).Select(n => n.Code).ToArray(); - str += $"\n [{i:x4}]: Dynamic ({string.Join(' ', index)})"; - i += length; - } else*/ - str += $"\n [{i:x4}]: {instruction}".PadRight(32); - /*if (instruction.OpCode == OpCode.Constant) { - i++; // i know, i know - str += $" : {Constants[Instructions.Subset(i, 8).Select(n => n.Code).ToArray().ToInt64()]}"; - i += 8; - }*/ - } - return str; - } + public string Debug(DebugLevel level = DebugLevel.None) + { + string str = Debugger.GetContextString(this); + for (int i = 0; i < Instructions.Count; i++) { + var instruction = Instructions[i]; + /*if ((instruction.Code & 0x80) == 1) { + // dynamic + int length = instruction.Code & (0x80 - 1); + byte[] index = Instructions.Subset(i + 1, length).Select(n => n.Code).ToArray(); + str += $"\n [{i:x4}]: Dynamic ({string.Join(' ', index)})"; + i += length; + } else*/ + str += $"\n [{i:x4}]: {instruction}".PadRight(32); + /*if (instruction.OpCode == OpCode.Constant) { + i++; // i know, i know + str += $" : {Constants[Instructions.Subset(i, 8).Select(n => n.Code).ToArray().ToInt64()]}"; + i += 8; + }*/ + } + return str; + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Compilation/Digester.cs b/Qrakhen.Qamp.Core/Compilation/Digester.cs index 41f7e41..790d26b 100644 --- a/Qrakhen.Qamp.Core/Compilation/Digester.cs +++ b/Qrakhen.Qamp.Core/Compilation/Digester.cs @@ -18,24 +18,24 @@ public enum FunctionType { Function, Constructor, Method, Code } internal class CompilerState { - public readonly IReader Reader; - public Token Current; - public Token Previous; - public TokenPosition ErrorPosition = TokenPosition.None; - public TokenPosition CurrentPosition => Reader.CurrentPosition; - public bool HadError => !ErrorPosition.IsNone; - public bool Done => Reader.Done; + public readonly IReader Reader; + public Token Current; + public Token Previous; + public TokenPosition ErrorPosition = TokenPosition.None; + public TokenPosition CurrentPosition => Reader.CurrentPosition; + public bool HadError => !ErrorPosition.IsNone; + public bool Done => Reader.Done; - public bool ThrowOnError { get; set; } = true; + public bool ThrowOnError { get; set; } = true; - public Builder Builder; - public FunctionBuilder Function => Builder.Function; - public long CurrentInstruction => Function.Segment.Instructions.Count; + public Builder Builder; + public FunctionBuilder Function => Builder.Function; + public long CurrentInstruction => Function.Segment.Instructions.Count; } public class DigesterProvider { - public object ExpressionDigester; // etc. + public object ExpressionDigester; // etc. } public abstract class xDigester @@ -45,833 +45,850 @@ public abstract class xDigester public class Digester : ISteppable { - private readonly CompilerState _compiler; + private readonly CompilerState _compiler; - public event Action? Error; + public event Action? Error; - private readonly ILogger _logger = LoggerService.Get(); - private readonly IReader _reader; + private readonly ILogger _logger = LoggerService.Get(); + private readonly IReader _reader; - internal FunctionBuilder Function => Builder.Function; + internal FunctionBuilder Function => Builder.Function; - internal Token Current; - internal Token Previous; + internal Token Current; + internal Token Previous; - public Builder Builder { get; private set; } - public ClassBuilder? ClassBuilder { get; private set; } - public bool ThrowOnError { get; set; } = true; + public Builder Builder { get; private set; } + public ClassBuilder? ClassBuilder { get; private set; } + public bool ThrowOnError { get; set; } = true; - public bool HadError => !ErrorPosition.IsNone; - public bool Done => _reader.Done; + public bool HadError => !ErrorPosition.IsNone; + public bool Done => _reader.Done; - public long CurrentInstruction => Function.Segment.Instructions.Count; - public TokenPosition CurrentPosition => _reader.CurrentPosition; - public TokenPosition ErrorPosition { get; private set; } = TokenPosition.None; + public long CurrentInstruction => Function.Segment.Instructions.Count; + public TokenPosition CurrentPosition => _reader.CurrentPosition; + public TokenPosition ErrorPosition { get; private set; } = TokenPosition.None; - public Digester(IReader reader) - { - Builder = CreateBuilder(FunctionType.Code); - _reader = reader; - } + public Digester(IReader reader) + { + Builder = CreateBuilder(FunctionType.Code); + _reader = reader; + } - public Function Digest() - { + public Function Digest() + { #if LOG _logger.Method(); #endif - TokenPosition previousPosition = _reader.CurrentPosition; - Next(); - while (!Done && !Match(T.Eof)) { - Token token = Current; + TokenPosition previousPosition = _reader.CurrentPosition; + Next(); + while (!Done && !Match(T.Eof)) { + Token token = Current; #if LOG _logger.Verbose($"Digesting {token}"); #endif - if (previousPosition == _reader.CurrentPosition) { - ErrorAtCurrent("Loop detected / could not digest further"); - break; - } - Process(); - } + if (previousPosition == _reader.CurrentPosition) { + ErrorAtCurrent("Loop detected / could not digest further"); + break; + } + Process(); + } - SegmentBuilder _debug = Builder.Function.Segment; - Function function = FinishBuilder(); + SegmentBuilder _debug = Builder.Function.Segment; + Function function = FinishBuilder(); #if LOG _logger.Debug($"Digest done, instruction set:"); #endif #if LOG _logger.Verbose(_debug.Debug()); #endif - return function; - } + return function; + } - internal Builder CreateBuilder(FunctionType type) - { - Builder builder = new(type, Builder); + internal Builder CreateBuilder(FunctionType type) + { + Builder builder = new(type, Builder); - if (type != FunctionType.Code) - builder.Function.Name = Previous.Value!; + if (type != FunctionType.Code) + builder.Function.Name = Previous.Value!; - builder.Locals.Push(new Local(type == FunctionType.Function ? "" : "this", 0)); - Builder = builder; - return Builder; - } + builder.Locals.Push(new Local(type == FunctionType.Function ? "" : "this", 0)); + Builder = builder; + return Builder; + } - internal Function FinishBuilder() - { - EmitReturn(); - Function function = Builder.Function.Build(); - Builder = Builder.Outer; - return function; - } + internal Function FinishBuilder() + { + EmitReturn(); + Function function = Builder.Function.Build(); + Builder = Builder.Outer; + return function; + } - internal void Process() - { + internal void Process() + { #if LOG _logger.Method(); #endif - if (Match(T.Class)) DeclareClass(); - else if (Match(T.Function)) DeclareFunction(); - else if (Match(T.Var)) DeclareVariable(); - else Statement(); - } + if (Match(T.Class)) + DeclareClass(); + else if (Match(T.Function)) + DeclareFunction(); + else if (Match(T.Var)) + DeclareVariable(); + else + Statement(); + } - internal void Statement() - { + internal void Statement() + { #if LOG _logger.Method(); #endif - if (Match(T.If)) If(); - else if (Match(T.Else)) Else(); - else if (Match(T.While)) While(); - else if (Match(T.Do)) Do(); - else if (Match(T.For)) For(); - else if (Match(T.Return)) Return(); - else if (Match(T.TypeOf)) TypeOf(); - else if (Match(T.Print)) Print(); - else if (Match(T.PrintStack)) PrintStack(); - else if (Match(T.PrintGlobals)) PrintGlobals(); - else if (Match(T.PrintExpr)) PrintExpr(); - else if (Match(T.Export)) Export(); - else if (Match(T.Import)) Import(); - else if (Match(T.ContextOpen)) Context(); - else Expression(); - } + if (Match(T.If)) + If(); + else if (Match(T.Else)) + Else(); + else if (Match(T.While)) + While(); + else if (Match(T.Do)) + Do(); + else if (Match(T.For)) + For(); + else if (Match(T.Return)) + Return(); + else if (Match(T.TypeOf)) + TypeOf(); + else if (Match(T.Print)) + Print(); + else if (Match(T.PrintStack)) + PrintStack(); + else if (Match(T.PrintGlobals)) + PrintGlobals(); + else if (Match(T.PrintExpr)) + PrintExpr(); + else if (Match(T.Export)) + Export(); + else if (Match(T.Import)) + Import(); + else if (Match(T.ContextOpen)) + Context(); + else + Expression(); + } - internal void Expression() - { + internal void Expression() + { #if LOG _logger.Method(); #endif - ParseExpression(); - if (Builder.Type == FunctionType.Code && Check(T.Eof)) - Emit(Op.Print); // if we got presented with only an expression on top-level code and no ; at the end, - // we assume the user wants to see the value. - else { - Consume(T.Semicolon, "Expected ';' after statement"); - Emit(Op.Pop); // in an expression statement, we definitely do not want to remain the value on stack, - // as it would fuck over the entire stack for the rest of the execution. - // not pushing it, e.g. with a flag to the Expression() call, would be a good todo idea. - // - // a tad bit older me: it's a terrible idea as return a = b; wouldn't work anymore - } - } + ParseExpression(); + if (Builder.Type == FunctionType.Code && Check(T.Eof)) + Emit(Op.Print); // if we got presented with only an expression on top-level code and no ; at the end, + // we assume the user wants to see the value. + else { + Consume(T.Semicolon, "Expected ';' after statement"); + Emit(Op.Pop); // in an expression statement, we definitely do not want to remain the value on stack, + // as it would fuck over the entire stack for the rest of the execution. + // not pushing it, e.g. with a flag to the Expression() call, would be a good todo idea. + // + // a tad bit older me: it's a terrible idea as return a = b; wouldn't work anymore + } + } - internal void ParseExpression() => WeightedDigest(Weight.Assign); + internal void ParseExpression() => WeightedDigest(Weight.Assign); - internal void Context() - { + internal void Context() + { #if LOG _logger.Method(); #endif - BeginScope(); - Block(); - EndScope(); - } + BeginScope(); + Block(); + EndScope(); + } - internal void Block() - { + internal void Block() + { #if LOG _logger.Method(); #endif - while (!Check(T.ContextClose) && !Check(T.Eof)) - Process(); - Consume(T.ContextClose, "Expected '}' after context"); - } + while (!Check(T.ContextClose) && !Check(T.Eof)) + Process(); + Consume(T.ContextClose, "Expected '}' after context"); + } - internal void WeightedDigest(Weight precedence) - { + internal void WeightedDigest(Weight precedence) + { #if LOG _logger.Method(); #endif - Next(); - Rule rule = ExpressionParser.Get(Previous.Type); - if (rule.Prefix == null) { - ErrorAtCurrent("Expected expression"); + Next(); + Rule rule = ExpressionParser.Get(Previous.Type); + if (rule.Prefix == null) { + ErrorAtCurrent("Expected expression"); + return; + } + + bool canAssign = precedence <= Weight.Assign; + rule.Prefix(this, canAssign); + + while (precedence <= ExpressionParser.Get(Current.Type).Weight) { + Next(); + ExpressionParser.Get(Previous.Type).Infix?.Invoke(this, canAssign); + } + + if (canAssign && Match(T.Equal)) + ErrorAtCurrent("Invalid assignment target."); + } + + internal void DeclareClass() + { +#if LOG + _logger.Method(); +#endif + Consume(T.Identifier, "Expected a class name."); + // we need both a global name constant and a local declaration for this class + string name = Previous.Value!; + long identifier = IdentifierConstant(name); + DeclareLocal(name); + EmitDynamic(Op.Class, identifier); + DefineVariable(identifier); + ClassBuilder = new ClassBuilder { + Outer = ClassBuilder, + Name = name, + IsDerived = false + }; + + if (Match(T.Colon)) { + Consume(T.Identifier, "Expected base class name.", false); + ExpressionParser.Variable(this, false); + if (name == Previous.Value!) + ErrorAtPrevious($"Class {name} can not inherit from itself!"); + + // Add base reference by injecting a synthetic base variable into a virtual scope + BeginScope(); + AddLocal("base"); + DefineVariable(0); + + ExpressionParser.Variable(this, name, false); + ClassBuilder.IsDerived = true; + } + + ExpressionParser.Variable(this, name, false); + Consume(T.ContextOpen, "Expected '{' for class body declaration.", false); + while (!Check(T.ContextClose) && !Check(T.Eof)) + DeclareMember(); + + Consume(T.ContextClose, "Expected '}' to end class body declaration.", false); + Emit(Op.Pop); + + if (ClassBuilder.IsDerived) + EndScope(); + + ClassBuilder = ClassBuilder.Outer; + } + + internal void DeclareFunction() + { +#if LOG + _logger.Method(); +#endif + long global = ParseVariable(); + InitializeLocal(); + CreateFunction(FunctionType.Function); + DefineVariable(global); + } + + internal void DeclareMember() + { + // todo: only methods allowed atm, add fields and shit too +#if LOG + _logger.Method(); +#endif + Consume(T.Identifier, "Expected method name.", false); + long identifier = IdentifierConstant(Previous.Value!); + FunctionType type = FunctionType.Method; + if (Previous.Value == ClassBuilder?.Name) + type = FunctionType.Constructor; + CreateFunction(type); + EmitDynamic(Op.Method, identifier); + } + + internal void DeclareVariable() + { +#if LOG + _logger.Method(); +#endif + long global = ParseVariable(); + if (Match(T.Equal)) + ParseExpression(); + else + Emit(Op.Null); + Consume(T.Semicolon, "missing ; after variable declaration"); + DefineVariable(global); + } + + internal void Export() + { +#if LOG + _logger.Method(); +#endif + throw new NotImplementedException($"Import is not yet implemented. Sorry, it's difficult."); + } + + internal void Import() + { +#if LOG + _logger.Method(); +#endif + throw new NotImplementedException($"Import is not yet implemented. Sorry, it's difficult."); + } + + internal void If() + { +#if LOG + _logger.Method(); +#endif + Consume(T.GroupOpen, "Expected '(' after if"); + ParseExpression(); + Consume(T.GroupClose, "Expected ')' after condition"); + + long then = EmitJump(Op.JumpIfFalse); + Emit(Op.Pop); + Statement(); + + long @else = EmitJump(Op.Jump); + + PatchJump(then); + Emit(Op.Pop); + + if (Match(T.Else)) + Statement(); + + PatchJump(@else); + } + + internal void Else() + { +#if LOG + _logger.Method(); +#endif + ErrorAtPrevious("This 'else' is very alone :( Have you meant to place it after an 'if'?"); + } + + internal void While() + { +#if LOG + _logger.Method(); +#endif + long start = Function.CurrentInstruction; + Consume(T.GroupOpen, "Expected while condition to be placed inside parentheses. Missing '('.", false); + ParseExpression(); + Consume(T.GroupClose, "Expected while condition to be placed inside parentheses. Missing ')'.", false); + long exit = EmitJump(Op.JumpIfFalse); + Emit(Op.Pop); + Statement(); + EmitLoop(start); + PatchJump(exit); + Emit(Op.Pop); + } + + internal void Do() + { +#if LOG + _logger.Method(); +#endif + // todo: just do a while loop here with synthetic counter variables checked at end + throw new NotImplementedException(); + } + + internal void For() + { +#if LOG + _logger.Method(); +#endif + BeginScope(); + Consume(T.GroupOpen, "Expected '(' after for statement"); + if (Match(T.Semicolon)) { + // nothing + } else if (Match(T.Var)) { + DeclareVariable(); + } else { + Expression(); + } + + long start = Function.CurrentInstruction; + long exit = -1; + if (!Match(T.Semicolon)) { + ParseExpression(); + Consume(T.Semicolon, "Expected ';' after condition"); + exit = EmitJump(Op.JumpIfFalse); + Emit(Op.Pop); + } + + if (!Match(T.GroupClose)) { + long body = EmitJump(Op.Jump); + long increment = Function.Segment.Instructions.Count; + ParseExpression(); + Emit(Op.Pop); + Consume(T.GroupClose, "Expected ')' after for clause"); + + EmitLoop(start); + start = increment; + PatchJump(body); + } + + Statement(); + EmitLoop(start); + if (exit > -1) { + PatchJump(exit); + Emit(Op.Pop); + } + + EndScope(); + } + + internal void Return() + { +#if LOG + _logger.Method(); +#endif + if (Builder.Type == FunctionType.Code) { + ErrorAtPrevious($"Interesting approach, but that won't work."); + return; + } + + if (Match(T.Semicolon)) { + EmitReturn(); + } else { + if (Builder.Type == FunctionType.Constructor) { + ErrorAtPrevious($"We're not returning from a constructor where I'm from."); return; - } + } - bool canAssign = precedence <= Weight.Assign; - rule.Prefix(this, canAssign); + ParseExpression(); + Consume(T.Semicolon, $"Expected ';' after return."); + Emit(Op.Return); + } + } - while (precedence <= ExpressionParser.Get(Current.Type).Weight) { - Next(); - ExpressionParser.Get(Previous.Type).Infix?.Invoke(this, canAssign); - } - - if (canAssign && Match(T.Equal)) - ErrorAtCurrent("Invalid assignment target."); - } - - internal void DeclareClass() - { + internal void Print() + { #if LOG _logger.Method(); #endif - Consume(T.Identifier, "Expected a class name."); - // we need both a global name constant and a local declaration for this class - string name = Previous.Value!; - long identifier = IdentifierConstant(name); - DeclareLocal(name); - EmitDynamic(Op.Class, identifier); - DefineVariable(identifier); - ClassBuilder = new ClassBuilder { - Outer = ClassBuilder, - Name = name, - IsDerived = false - }; + ParseExpression(); + Consume(T.Semicolon, "Expected ';' after print call."); + Emit(Op.Print); + } - if (Match(T.Colon)) - { - Consume(T.Identifier, "Expected base class name.", false); - ExpressionParser.Variable(this, false); - if (name == Previous.Value!) - ErrorAtPrevious($"Class {name} can not inherit from itself!"); - - // Add base reference by injecting a synthetic base variable into a virtual scope - BeginScope(); - AddLocal("base"); - DefineVariable(0); - - ExpressionParser.Variable(this, name, false); - ClassBuilder.IsDerived = true; - } - - ExpressionParser.Variable(this, name, false); - Consume(T.ContextOpen, "Expected '{' for class body declaration.", false); - while (!Check(T.ContextClose) && !Check(T.Eof)) - DeclareMember(); - - Consume(T.ContextClose, "Expected '}' to end class body declaration.", false); - Emit(Op.Pop); - - if (ClassBuilder.IsDerived) - EndScope(); - - ClassBuilder = ClassBuilder.Outer; - } - - internal void DeclareFunction() - { + internal void PrintGlobals() + { #if LOG _logger.Method(); #endif - long global = ParseVariable(); - InitializeLocal(); - CreateFunction(FunctionType.Function); - DefineVariable(global); - } + Consume(T.Semicolon, "Expected ';' after print call."); + Emit(Op.PrintGlobals); + } - internal void DeclareMember() - { - // todo: only methods allowed atm, add fields and shit too + internal void PrintStack() + { #if LOG _logger.Method(); #endif - Consume(T.Identifier, "Expected method name.", false); - long identifier = IdentifierConstant(Previous.Value!); - FunctionType type = FunctionType.Method; - if (Previous.Value == ClassBuilder?.Name) - type = FunctionType.Constructor; - CreateFunction(type); - EmitDynamic(Op.Method, identifier); - } + Consume(T.Semicolon, "Expected ';' after print call."); + Emit(Op.PrintStack); + } - internal void DeclareVariable() - { + internal void PrintExpr() + { #if LOG _logger.Method(); #endif - long global = ParseVariable(); - if (Match(T.Equal)) - ParseExpression(); - else - Emit(Op.Null); - Consume(T.Semicolon, "missing ; after variable declaration"); - DefineVariable(global); - } + Consume(T.Semicolon, "Expected ';' after print call."); + Emit(Op.PrintExpr); + } - internal void Export() - { + internal void TypeOf() + { #if LOG _logger.Method(); #endif - throw new NotImplementedException($"Import is not yet implemented. Sorry, it's difficult."); - } + ParseExpression(); + Emit(Op.Typeof); + } - internal void Import() - { + internal void BeginScope() + { #if LOG _logger.Method(); #endif - throw new NotImplementedException($"Import is not yet implemented. Sorry, it's difficult."); - } + Builder.ScopeDepth++; + } - internal void If() - { + internal void EndScope() + { #if LOG _logger.Method(); #endif - Consume(T.GroupOpen, "Expected '(' after if"); - ParseExpression(); - Consume(T.GroupClose, "Expected ')' after condition"); - - long then = EmitJump(Op.JumpIfFalse); - Emit(Op.Pop); - Statement(); - - long @else = EmitJump(Op.Jump); - - PatchJump(then); - Emit(Op.Pop); - - if (Match(T.Else)) - Statement(); - - PatchJump(@else); - } - - internal void Else() - { -#if LOG - _logger.Method(); -#endif - ErrorAtPrevious("This 'else' is very alone :( Have you meant to place it after an 'if'?"); - } - - internal void While() - { -#if LOG - _logger.Method(); -#endif - long start = Function.CurrentInstruction; - Consume(T.GroupOpen, "Expected while condition to be placed inside parentheses. Missing '('.", false); - ParseExpression(); - Consume(T.GroupClose, "Expected while condition to be placed inside parentheses. Missing ')'.", false); - long exit = EmitJump(Op.JumpIfFalse); - Emit(Op.Pop); - Statement(); - EmitLoop(start); - PatchJump(exit); - Emit(Op.Pop); - } - - internal void Do() - { -#if LOG - _logger.Method(); -#endif - // todo: just do a while loop here with synthetic counter variables checked at end - throw new NotImplementedException(); - } - - internal void For() - { -#if LOG - _logger.Method(); -#endif - BeginScope(); - Consume(T.GroupOpen, "Expected '(' after for statement"); - if (Match(T.Semicolon)) { - // nothing - } else if (Match(T.Var)) { - DeclareVariable(); - } else { - Expression(); - } - - long start = Function.CurrentInstruction; - long exit = -1; - if (!Match(T.Semicolon)) { - ParseExpression(); - Consume(T.Semicolon, "Expected ';' after condition"); - exit = EmitJump(Op.JumpIfFalse); + Builder.ScopeDepth--; + while (Builder.Locals.Count > 0 && + Builder.Locals.Peek().Depth > Builder.ScopeDepth) { + if (Builder.Locals.Peek().IsCaptured) { + Emit(Op.CloseOuter); + } else { Emit(Op.Pop); - } + } + Builder.Locals.Pop(); + } + } - if (!Match(T.GroupClose)) { - long body = EmitJump(Op.Jump); - long increment = Function.Segment.Instructions.Count; - ParseExpression(); - Emit(Op.Pop); - Consume(T.GroupClose, "Expected ')' after for clause"); - - EmitLoop(start); - start = increment; - PatchJump(body); - } - - Statement(); - EmitLoop(start); - if (exit > -1) { - PatchJump(exit); - Emit(Op.Pop); - } - - EndScope(); - } - - internal void Return() - { + internal void CreateFunction(FunctionType type) + { #if LOG _logger.Method(); #endif - if (Builder.Type == FunctionType.Code) { - ErrorAtPrevious($"Interesting approach, but that won't work."); - return; - } + Builder next = CreateBuilder(type); + BeginScope(); + Consume(T.GroupOpen, "Expected '(' to start argument list."); + if (!Check(T.GroupClose)) { + do { + Builder.Function.ArgumentCount++; + if (Builder.Function.ArgumentCount > 0xFF) + ErrorAtCurrent($"In the name of the lord, how many arguments do you need?"); + DefineVariable(ParseVariable()); + } while (Match(T.Comma)); + } + Consume(T.GroupClose, "Expected ')' after argument list."); + Consume(T.ContextOpen, "Expected function body"); + Block(); + Function function = FinishBuilder(); + Emit(Op.Context); + EmitDynamic(MakeConstant(Obj.Create(function))); + for (int i = 0; i < function.OuterCount; i++) { + Outer outer = next.Outers.Get(i); + Emit(outer.IsLocal ? 1 : 0); + EmitDynamic(outer.Index); + } + } - if (Match(T.Semicolon)) { - EmitReturn(); - } else { - if (Builder.Type == FunctionType.Constructor) { - ErrorAtPrevious($"We're not returning from a constructor where I'm from."); - return; - } + internal long ResolveLocal(Builder builder, string name) + { + for (int i = 0; i < builder.Locals.Count; i++) { + if (builder.Locals[i].Name == name) + return i; + } - ParseExpression(); - Consume(T.Semicolon, $"Expected ';' after return."); - Emit(Op.Return); - } - } + return -1; + } - internal void Print() - { -#if LOG - _logger.Method(); -#endif - ParseExpression(); - Consume(T.Semicolon, "Expected ';' after print call."); - Emit(Op.Print); - } - - internal void PrintGlobals() - { -#if LOG - _logger.Method(); -#endif - Consume(T.Semicolon, "Expected ';' after print call."); - Emit(Op.PrintGlobals); - } - - internal void PrintStack() - { -#if LOG - _logger.Method(); -#endif - Consume(T.Semicolon, "Expected ';' after print call."); - Emit(Op.PrintStack); - } - - internal void PrintExpr() - { -#if LOG - _logger.Method(); -#endif - Consume(T.Semicolon, "Expected ';' after print call."); - Emit(Op.PrintExpr); - } - - internal void TypeOf() - { -#if LOG - _logger.Method(); -#endif - ParseExpression(); - Emit(Op.Typeof); - } - - internal void BeginScope() - { -#if LOG - _logger.Method(); -#endif - Builder.ScopeDepth++; - } - - internal void EndScope() - { -#if LOG - _logger.Method(); -#endif - Builder.ScopeDepth--; - while (Builder.Locals.Count > 0 && - Builder.Locals.Peek().Depth > Builder.ScopeDepth) { - if (Builder.Locals.Peek().IsCaptured) { - Emit(Op.CloseOuter); - } else { - Emit(Op.Pop); - } - Builder.Locals.Pop(); - } - } - - internal void CreateFunction(FunctionType type) - { -#if LOG - _logger.Method(); -#endif - Builder next = CreateBuilder(type); - BeginScope(); - Consume(T.GroupOpen, "Expected '(' to start argument list."); - if (!Check(T.GroupClose)) { - do { - Builder.Function.ArgumentCount++; - if (Builder.Function.ArgumentCount > 0xFF) - ErrorAtCurrent($"In the name of the lord, how many arguments do you need?"); - DefineVariable(ParseVariable()); - } while (Match(T.Comma)); - } - Consume(T.GroupClose, "Expected ')' after argument list."); - Consume(T.ContextOpen, "Expected function body"); - Block(); - Function function = FinishBuilder(); - Emit(Op.Context); - EmitDynamic(MakeConstant(Obj.Create(function))); - for (int i = 0; i < function.OuterCount; i++) { - Outer outer = next.Outers.Get(i); - Emit(outer.IsLocal ? 1 : 0); - EmitDynamic(outer.Index); - } - } - - internal long ResolveLocal(Builder builder, string name) - { - for (int i = 0; i < builder.Locals.Count; i++) { - if (builder.Locals[i].Name == name) - return i; - } - - return -1; - } - - internal void AddLocal(string? name) - { + internal void AddLocal(string? name) + { #if LOG _logger.Method(name); #endif - Builder.Locals.Push(new Local(ThrowIfEmpty(name), -1)); - } + Builder.Locals.Push(new Local(ThrowIfEmpty(name), -1)); + } - internal void DeclareLocal(string? name) - { - if (Builder.ScopeDepth == 0) - return; + internal void DeclareLocal(string? name) + { + if (Builder.ScopeDepth == 0) + return; #if LOG _logger.Method(name); #endif - for (int i = 0; i < Builder.Locals.Count; i++) { - Local local = Builder.Locals[i]; - // skip if the most recent local isn't even in our scope - if (local.Depth != -1 && local.Depth < Builder.ScopeDepth) - break; + for (int i = 0; i < Builder.Locals.Count; i++) { + Local local = Builder.Locals[i]; + // skip if the most recent local isn't even in our scope + if (local.Depth != -1 && local.Depth < Builder.ScopeDepth) + break; - if (ThrowIfEmpty(name).Equals(local.Name)) - ErrorAtCurrent($"A variable by the name {name} already exists in the current scope."); - } - AddLocal(name); - } + if (ThrowIfEmpty(name).Equals(local.Name)) + ErrorAtCurrent($"A variable by the name {name} already exists in the current scope."); + } + AddLocal(name); + } - internal long AddOuter(Builder builder, long index, bool isLocal) - { - for (int i = 0; i < builder.Function.OuterCount; i++) { - Outer outer = builder.Outers[i]; - if (outer.Index == index && outer.IsLocal == isLocal) - return i; - } + internal long AddOuter(Builder builder, long index, bool isLocal) + { + for (int i = 0; i < builder.Function.OuterCount; i++) { + Outer outer = builder.Outers[i]; + if (outer.Index == index && outer.IsLocal == isLocal) + return i; + } - builder.Outers.Push(new Outer(index, isLocal)); - return builder.Outers.Count - 1; - } + builder.Outers.Push(new Outer(index, isLocal)); + return builder.Outers.Count - 1; + } - internal long ResolveOuter(Builder builder, string name) - { - if (builder.Outer == null) - return -1; + internal long ResolveOuter(Builder builder, string name) + { + if (builder.Outer == null) + return -1; - long local = ResolveLocal(builder.Outer, name); - if (local > -1) { - Local element = builder.Outer.Locals.Get(local); - element.IsCaptured = true; - builder.Outer.Locals.Set(local, element); - return AddOuter(builder, local, true); - } + long local = ResolveLocal(builder.Outer, name); + if (local > -1) { + Local element = builder.Outer.Locals.Get(local); + element.IsCaptured = true; + builder.Outer.Locals.Set(local, element); + return AddOuter(builder, local, true); + } - long outer = ResolveOuter(builder.Outer, name); - if (outer > -1) - return AddOuter(builder, outer, false); + long outer = ResolveOuter(builder.Outer, name); + if (outer > -1) + return AddOuter(builder, outer, false); - return -1; - } + return -1; + } - internal long IdentifierConstant(string? name) - { + internal long IdentifierConstant(string? name) + { #if LOG _logger.Method(name); #endif - return MakeConstant(String.Make(name ?? - throw new TokenException("Empty string value for identifier detected", _reader, Current))); - } + return MakeConstant(String.Make(name ?? + throw new TokenException("Empty string value for identifier detected", _reader, Current))); + } - internal long MakeConstant(Value value) - { + internal long MakeConstant(Value value) + { #if LOG _logger.Method(value.ToString()); #endif - long constant = Function.Segment.Constants.Add(value); + long constant = Function.Segment.Constants.Add(value); #if LOG _logger.Verbose($"Registered constant {value} at index {constant}"); #endif - return constant; - } + return constant; + } - internal long ParseVariable() - { + internal long ParseVariable() + { #if LOG _logger.Method(); #endif - string? name = Consume(T.Identifier, "Missing identifier for variable").Value; - if (Builder.ScopeDepth == 0) - return IdentifierConstant(name); - DeclareLocal(name); - return 0; - } + string? name = Consume(T.Identifier, "Missing identifier for variable").Value; + if (Builder.ScopeDepth == 0) + return IdentifierConstant(name); + DeclareLocal(name); + return 0; + } - internal void InitializeLocal() - { - if (Builder.ScopeDepth == 0) - return; + internal void InitializeLocal() + { + if (Builder.ScopeDepth == 0) + return; #if LOG _logger.Method(); #endif - var local = Builder.Locals.Peek(); - local.Depth = Builder.ScopeDepth; - Builder.Locals.Set(Builder.Locals.Position - 1, local); - } + var local = Builder.Locals.Peek(); + local.Depth = Builder.ScopeDepth; + Builder.Locals.Set(Builder.Locals.Position - 1, local); + } - internal void DefineVariable(long index) - { + internal void DefineVariable(long index) + { #if LOG _logger.Method(index.ToString()); #endif - if (Builder.ScopeDepth > 0) { - InitializeLocal(); - } else { - Emit(Op.DefineGlobal); - EmitDynamic(index); - } - } + if (Builder.ScopeDepth > 0) { + InitializeLocal(); + } else { + Emit(Op.DefineGlobal); + EmitDynamic(index); + } + } - internal byte Arguments() - { - byte count = 0; - if (!Check(T.GroupClose)) { - do { - ParseExpression(); - if (count++ >= 0xFF) - ErrorAtCurrent("How many arguments do you need?"); - } while (Match(T.Comma)); - } + internal byte Arguments() + { + byte count = 0; + if (!Check(T.GroupClose)) { + do { + ParseExpression(); + if (count++ >= 0xFF) + ErrorAtCurrent("How many arguments do you need?"); + } while (Match(T.Comma)); + } - Consume(T.GroupClose, "Expected ')' after argument list"); - return count; - } + Consume(T.GroupClose, "Expected ')' after argument list"); + return count; + } - /// - /// Primary Emit. - /// - internal void Emit(params byte[] data) - { + /// + /// Primary Emit. + /// + internal void Emit(params byte[] data) + { #if LOG if (data.Length == 1) _logger.Verbose($"Emitting {new Instruction(data[0])}"); else if (data.Length > 1) _logger.Verbose($"Emitting {string.Join(' ', data)}"); #endif - foreach (var value in data) - Function.Segment.Instructions.Add(value); - } + foreach (var value in data) + Function.Segment.Instructions.Add(value); + } - /// - /// Sets instruction bytes at - /// - internal void Patch(byte[] bytes, long position) - { - for (int i = 0; i < bytes.Length; i++) - { - Function.Segment.Instructions[position + i] = bytes[i]; - } - } + /// + /// Sets instruction bytes at + /// + internal void Patch(byte[] bytes, long position) + { + for (int i = 0; i < bytes.Length; i++) { + Function.Segment.Instructions[position + i] = bytes[i]; + } + } - internal void EmitConstant(Value constant) - { - Emit(Op.Constant); - EmitDynamic(MakeConstant(constant)); - } + internal void EmitConstant(Value constant) + { + Emit(Op.Constant); + EmitDynamic(MakeConstant(constant)); + } - internal long EmitJump(Instruction instruction) - { - Emit(instruction); - Emit(-1L); - return CurrentInstruction - sizeof(long); - } + internal long EmitJump(Instruction instruction) + { + Emit(instruction); + Emit(-1L); + return CurrentInstruction - sizeof(long); + } - internal void PatchJump(long offset) - { - long target = CurrentInstruction - offset - sizeof(long); - Patch(target.GetBytes(), offset); - } + internal void PatchJump(long offset) + { + long target = CurrentInstruction - offset - sizeof(long); + Patch(target.GetBytes(), offset); + } - internal void EmitLoop(long start) - { - Emit(Op.Loop); - long offset = Function.Segment.Instructions.Count - start + sizeof(long); - Emit(offset); - } + internal void EmitLoop(long start) + { + Emit(Op.Loop); + long offset = Function.Segment.Instructions.Count - start + sizeof(long); + Emit(offset); + } - /// - /// Emits a dynamic range of bytes into the instruction set. - /// - internal void EmitDynamic(byte[] data) - { - if (data.Length > 1) - Emit((byte)(data.Length | 0x80)); // 0x80 flag for length marker, anything else is direct value - Emit(data); - } + /// + /// Emits a dynamic range of bytes into the instruction set. + /// + internal void EmitDynamic(byte[] data) + { + if (data.Length > 1) + Emit((byte)(data.Length | 0x80)); // 0x80 flag for length marker, anything else is direct value + Emit(data); + } - /// - /// Emits the given , and then adds using . - /// - internal void EmitDynamic(Instruction instruction, long data) - { - Emit(instruction); - EmitDynamic(data); - } + /// + /// Emits the given , and then adds using . + /// + internal void EmitDynamic(Instruction instruction, long data) + { + Emit(instruction); + EmitDynamic(data); + } - internal void EmitDynamic(long value) - => EmitDynamic(value.GetDynamicBytes()); + internal void EmitDynamic(long value) + => EmitDynamic(value.GetDynamicBytes()); - internal void Emit(Instruction instruction) - { - Emit(instruction.Code); - } + internal void Emit(Instruction instruction) + { + Emit(instruction.Code); + } - internal void Emit(Instruction instruction, byte[] data) - { - Emit(instruction); - Emit(data); - } + internal void Emit(Instruction instruction, byte[] data) + { + Emit(instruction); + Emit(data); + } - internal void Emit(IEnumerable instructions) - { - foreach (var i in instructions) - Emit(i); - } + internal void Emit(IEnumerable instructions) + { + foreach (var i in instructions) + Emit(i); + } - internal void EmitReturn() - { - if (Builder.Type == FunctionType.Constructor) { - Emit(Op.GetLocal, 0); - } else { - Emit(Op.Null); - } + internal void EmitReturn() + { + if (Builder.Type == FunctionType.Constructor) { + Emit(Op.GetLocal, 0); + } else { + Emit(Op.Null); + } - Emit(Op.Return); - } + Emit(Op.Return); + } - internal void Emit(params Instruction[] instructions) - => Emit(instructions.AsEnumerable()); + internal void Emit(params Instruction[] instructions) + => Emit(instructions.AsEnumerable()); - internal void Emit(short value) - => Emit(BitConverter.GetBytes(value)); + internal void Emit(short value) + => Emit(BitConverter.GetBytes(value)); - internal void Emit(int value) - => Emit(BitConverter.GetBytes(value)); + internal void Emit(int value) + => Emit(BitConverter.GetBytes(value)); - internal void Emit(long value) - => Emit(BitConverter.GetBytes(value)); + internal void Emit(long value) + => Emit(BitConverter.GetBytes(value)); - internal void Emit(ulong value) - => Emit(BitConverter.GetBytes(value)); + internal void Emit(ulong value) + => Emit(BitConverter.GetBytes(value)); - internal void Emit(double value) - => Emit(BitConverter.GetBytes(value)); + internal void Emit(double value) + => Emit(BitConverter.GetBytes(value)); - public Token Next() - { - Previous = Current; - return Current = _reader.NextToken(); - } - - internal Token Consume(T expected, string errorMessage, bool acceptEof = true) - { - if ((acceptEof && Current.Type == T.Eof) || Current.Type == expected) { - Next(); - return Previous; - } - ErrorAtCurrent(errorMessage); - return Token.Error(errorMessage); - } + public Token Next() + { + Previous = Current; + return Current = _reader.NextToken(); + } - internal bool Match(T type) - { - if (!Check(type)) - return false; - Next(); - return true; - } + internal Token Consume(T expected, string errorMessage, bool acceptEof = true) + { + if ((acceptEof && Current.Type == T.Eof) || Current.Type == expected) { + Next(); + return Previous; + } + ErrorAtCurrent(errorMessage); + return Token.Error(errorMessage); + } - internal bool Check(T type) - => Current.Type == type; + internal bool Match(T type) + { + if (!Check(type)) + return false; + Next(); + return true; + } - internal void ErrorAt(Token token, string errorMessage) - => ReportError(token, errorMessage); + internal bool Check(T type) + => Current.Type == type; - internal void ErrorAtCurrent(string errorMessage) - => ReportError(Current, errorMessage); + internal void ErrorAt(Token token, string errorMessage) + => ReportError(token, errorMessage); - internal void ErrorAtPrevious(string errorMessage) - => ReportError(Previous, errorMessage); + internal void ErrorAtCurrent(string errorMessage) + => ReportError(Current, errorMessage); - private void ReportError(Token token, string errorMessage) - { - #if LOG + internal void ErrorAtPrevious(string errorMessage) + => ReportError(Previous, errorMessage); + + private void ReportError(Token token, string errorMessage) + { +#if LOG _logger.Method(); #endif - ErrorPosition = token.Position; + ErrorPosition = token.Position; #if LOG _logger.Error($"At token index {token.Position}: {errorMessage}"); #endif - if (ThrowOnError) - throw new TokenException($"At token index {token.Position}: {errorMessage}", _reader, token); - Error?.Invoke(token, errorMessage); - } + if (ThrowOnError) + throw new TokenException($"At token index {token.Position}: {errorMessage}", _reader, token); + Error?.Invoke(token, errorMessage); + } - private string ThrowIfEmpty(string? value, string? message = $"Unexpected empty string detected") - { - if (string.IsNullOrEmpty(value)) - throw new TokenException("Empty string value for identifier detected", _reader, Current); - return value; - } + private string ThrowIfEmpty(string? value, string? message = $"Unexpected empty string detected") + { + if (string.IsNullOrEmpty(value)) + throw new TokenException("Empty string value for identifier detected", _reader, Current); + return value; + } } diff --git a/Qrakhen.Qamp.Core/Compilation/Digesters/IDigester.cs b/Qrakhen.Qamp.Core/Compilation/Digesters/IDigester.cs index e059a9b..903e67e 100644 --- a/Qrakhen.Qamp.Core/Compilation/Digesters/IDigester.cs +++ b/Qrakhen.Qamp.Core/Compilation/Digesters/IDigester.cs @@ -8,5 +8,5 @@ namespace Qrakhen.Qamp.Core.Compilation.Digesters; internal interface IDigester { - void Digest(CompilerState state); + void Digest(CompilerState state); } diff --git a/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs b/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs index 0206623..47961c0 100644 --- a/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs +++ b/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs @@ -7,304 +7,345 @@ namespace Qrakhen.Qamp.Core.Compilation; public static class ExpressionParser { - private static readonly Dictionary _rules = new(); + private static readonly Dictionary _rules = new(); - public static Rule Get(TokenType type) => _rules[type]; - - public static void And(Digester digester, bool canAssign) - { - long endJump = digester.EmitJump(OpCode.JumpIfFalse); + public static Rule Get(TokenType type) => _rules[type]; - digester.Emit(OpCode.Pop); - digester.WeightedDigest(Weight.And); + public static void And(Digester digester, bool canAssign) + { + long endJump = digester.EmitJump(OpCode.JumpIfFalse); - digester.PatchJump(endJump); - } + digester.Emit(OpCode.Pop); + digester.WeightedDigest(Weight.And); - static void Binary(Digester digester, bool canAssign) - { - TokenType operatorType = digester.Previous.Type; - Rule rule = Get(operatorType); - digester.WeightedDigest(rule.Weight + 1); + digester.PatchJump(endJump); + } - switch (operatorType) { - case TokenType.BangEqual: digester.Emit(OpCode.Equal, OpCode.Not); break; - case TokenType.EqualEqual: digester.Emit(OpCode.Equal); break; - case TokenType.Greater: digester.Emit(OpCode.Greater); break; - case TokenType.GreaterEqual: digester.Emit(OpCode.Less, OpCode.Not); break; - case TokenType.Less: digester.Emit(OpCode.Less); break; - case TokenType.LessEqual: digester.Emit(OpCode.Greater, OpCode.Not); break; - case TokenType.Plus: digester.Emit(OpCode.Add); break; - case TokenType.Minus: digester.Emit(OpCode.Subtract); break; - case TokenType.Star: digester.Emit(OpCode.Multiply); break; - case TokenType.Slash: digester.Emit(OpCode.Divide); break; - case TokenType.BitwiseAnd: digester.Emit(OpCode.BitwiseAnd); break; - case TokenType.BitwiseOr: digester.Emit(OpCode.BitwiseOr); break; - case TokenType.BitwiseXor: digester.Emit(OpCode.BitwiseXor); break; - case TokenType.BitwiseNot: digester.Emit(OpCode.BitwiseNot); break; - case TokenType.BitwiseLeft: digester.Emit(OpCode.BitwiseLeft); break; - case TokenType.BitwiseRight: digester.Emit(OpCode.BitwiseRight); break; - case TokenType.Increment: digester.Emit(OpCode.Increment); break; - case TokenType.Decrement: digester.Emit(OpCode.Decrement); break; - default: return; - } - } + static void Binary(Digester digester, bool canAssign) + { + TokenType operatorType = digester.Previous.Type; + Rule rule = Get(operatorType); + digester.WeightedDigest(rule.Weight + 1); - static void Call(Digester digester, bool canAssign) - { - byte count = digester.Arguments(); - digester.Emit(OpCode.Invoke, count); - } + switch (operatorType) { + case TokenType.BangEqual: + digester.Emit(OpCode.Equal, OpCode.Not); + break; + case TokenType.EqualEqual: + digester.Emit(OpCode.Equal); + break; + case TokenType.Greater: + digester.Emit(OpCode.Greater); + break; + case TokenType.GreaterEqual: + digester.Emit(OpCode.Less, OpCode.Not); + break; + case TokenType.Less: + digester.Emit(OpCode.Less); + break; + case TokenType.LessEqual: + digester.Emit(OpCode.Greater, OpCode.Not); + break; + case TokenType.Plus: + digester.Emit(OpCode.Add); + break; + case TokenType.Minus: + digester.Emit(OpCode.Subtract); + break; + case TokenType.Star: + digester.Emit(OpCode.Multiply); + break; + case TokenType.Slash: + digester.Emit(OpCode.Divide); + break; + case TokenType.BitwiseAnd: + digester.Emit(OpCode.BitwiseAnd); + break; + case TokenType.BitwiseOr: + digester.Emit(OpCode.BitwiseOr); + break; + case TokenType.BitwiseXor: + digester.Emit(OpCode.BitwiseXor); + break; + case TokenType.BitwiseNot: + digester.Emit(OpCode.BitwiseNot); + break; + case TokenType.BitwiseLeft: + digester.Emit(OpCode.BitwiseLeft); + break; + case TokenType.BitwiseRight: + digester.Emit(OpCode.BitwiseRight); + break; + case TokenType.Increment: + digester.Emit(OpCode.Increment); + break; + case TokenType.Decrement: + digester.Emit(OpCode.Decrement); + break; + default: + return; + } + } - static void Dot(Digester digester, bool canAssign) - { - digester.Consume(TokenType.Identifier, "Expected property name after '.'."); - long name = digester.IdentifierConstant(digester.Previous.Value); + static void Call(Digester digester, bool canAssign) + { + byte count = digester.Arguments(); + digester.Emit(OpCode.Invoke, count); + } - if (canAssign && digester.Match(TokenType.Equal)) { - digester.ParseExpression(); - digester.EmitDynamic(OpCode.SetMember, name); - } else if (digester.Match(TokenType.GroupOpen)) { - byte argCount = digester.Arguments(); - digester.EmitDynamic(OpCode.InvokeMember, name); - digester.Emit(argCount); - } else { - digester.EmitDynamic(OpCode.GetMember, name); - } - } + static void Dot(Digester digester, bool canAssign) + { + digester.Consume(TokenType.Identifier, "Expected property name after '.'."); + long name = digester.IdentifierConstant(digester.Previous.Value); - static void Literal(Digester digester, bool canAssign) - { - switch (digester.Previous.Type) { - case TokenType.False: - digester.Emit(OpCode.False); - break; - case TokenType.Null: - digester.Emit(OpCode.Null); - break; - case TokenType.True: - digester.Emit(OpCode.True); - break; - default: - break; - } - } + if (canAssign && digester.Match(TokenType.Equal)) { + digester.ParseExpression(); + digester.EmitDynamic(OpCode.SetMember, name); + } else if (digester.Match(TokenType.GroupOpen)) { + byte argCount = digester.Arguments(); + digester.EmitDynamic(OpCode.InvokeMember, name); + digester.Emit(argCount); + } else { + digester.EmitDynamic(OpCode.GetMember, name); + } + } - static void Group(Digester digester, bool canAssign) - { - digester.ParseExpression(); - digester.Consume(TokenType.GroupClose, "Expected ')' after expression."); - } + static void Literal(Digester digester, bool canAssign) + { + switch (digester.Previous.Type) { + case TokenType.False: + digester.Emit(OpCode.False); + break; + case TokenType.Null: + digester.Emit(OpCode.Null); + break; + case TokenType.True: + digester.Emit(OpCode.True); + break; + default: + break; + } + } - static void Array(Digester digester, bool canAssign) - { - int length = 0; - while (!digester.Check(TokenType.ArrayClose)) { - digester.ParseExpression(); - length++; - if (digester.Check(TokenType.Comma)) - digester.Next(); - else - break; - } - digester.Consume(TokenType.ArrayClose, "Expected ']' after array declaration"); - digester.EmitDynamic(OpCode.Array, length); // digester.MakeConstant(new Value((long)length))); - } + static void Group(Digester digester, bool canAssign) + { + digester.ParseExpression(); + digester.Consume(TokenType.GroupClose, "Expected ')' after expression."); + } - static void AddItem(Digester digester, bool canAssign) - { - digester.ParseExpression(); - digester.Emit(OpCode.AddItem); - } + static void Array(Digester digester, bool canAssign) + { + int length = 0; + while (!digester.Check(TokenType.ArrayClose)) { + digester.ParseExpression(); + length++; + if (digester.Check(TokenType.Comma)) + digester.Next(); + else + break; + } + digester.Consume(TokenType.ArrayClose, "Expected ']' after array declaration"); + digester.EmitDynamic(OpCode.Array, length); // digester.MakeConstant(new Value((long)length))); + } - static void Accessor(Digester digester, bool canAssign) - { - digester.ParseExpression(); - digester.Consume(TokenType.ArrayClose, "expected ] after array accessor"); - if (canAssign && digester.Match(TokenType.AddItem)) { - digester.ParseExpression(); - digester.Emit(OpCode.AddItem); - } else if (canAssign && digester.Match(TokenType.Equal)) { - digester.ParseExpression(); - digester.Emit(OpCode.SetItem); - } else { - digester.Emit(OpCode.GetItem); - } - } + static void AddItem(Digester digester, bool canAssign) + { + digester.ParseExpression(); + digester.Emit(OpCode.AddItem); + } - static void Number(Digester digester, bool canAssign) - { - Token token = digester.Previous; - string number = token.Value ?? ""; - TokenType type = token.Type; - Value value = default; - if (type == TokenType.Hexadecimal) - value = new Value(long.Parse(number, NumberStyles.HexNumber)); - else if (type == TokenType.Decimal) - value = new Value(double.Parse(number, NumberStyles.Float, CultureInfo.InvariantCulture)); - else if (type == TokenType.Integer) - value = new Value(long.Parse(number, NumberStyles.Integer)); - else - digester.ErrorAt(token, $"Could not parse number {number}"); - digester.EmitConstant(value); - } + static void Accessor(Digester digester, bool canAssign) + { + digester.ParseExpression(); + digester.Consume(TokenType.ArrayClose, "expected ] after array accessor"); + if (canAssign && digester.Match(TokenType.AddItem)) { + digester.ParseExpression(); + digester.Emit(OpCode.AddItem); + } else if (canAssign && digester.Match(TokenType.Equal)) { + digester.ParseExpression(); + digester.Emit(OpCode.SetItem); + } else { + digester.Emit(OpCode.GetItem); + } + } - static void Or(Digester digester, bool canAssign) - { - long elseJump = digester.EmitJump(OpCode.JumpIfFalse); - long endJump = digester.EmitJump(OpCode.Jump); + static void Number(Digester digester, bool canAssign) + { + Token token = digester.Previous; + string number = token.Value ?? ""; + TokenType type = token.Type; + Value value = default; + if (type == TokenType.Hexadecimal) + value = new Value(long.Parse(number, NumberStyles.HexNumber)); + else if (type == TokenType.Decimal) + value = new Value(double.Parse(number, NumberStyles.Float, CultureInfo.InvariantCulture)); + else if (type == TokenType.Integer) + value = new Value(long.Parse(number, NumberStyles.Integer)); + else + digester.ErrorAt(token, $"Could not parse number {number}"); + digester.EmitConstant(value); + } - digester.PatchJump(elseJump); - digester.Emit(OpCode.Pop); + static void Or(Digester digester, bool canAssign) + { + long elseJump = digester.EmitJump(OpCode.JumpIfFalse); + long endJump = digester.EmitJump(OpCode.Jump); - digester.WeightedDigest(Weight.Or); - digester.PatchJump(endJump); - } + digester.PatchJump(elseJump); + digester.Emit(OpCode.Pop); - static void String(Digester digester, bool canAssign) - { - digester.EmitConstant(Values.Objects.String.Make(digester.Previous.Value)); - } + digester.WeightedDigest(Weight.Or); + digester.PatchJump(endJump); + } - public static void Variable(Digester digester, string name, bool canAssign) - { - OpCode Get, Set; - long variable = digester.ResolveLocal(digester.Builder, name); - if (variable > -1) { - Get = OpCode.GetLocal; - Set = OpCode.SetLocal; - } else if ((variable = digester.ResolveOuter(digester.Builder, name)) > -1) { - Get = OpCode.GetOuter; - Set = OpCode.SetOuter; - } else { - variable = digester.IdentifierConstant(name); - Get = OpCode.GetGlobal; - Set = OpCode.SetGlobal; - } + static void String(Digester digester, bool canAssign) + { + digester.EmitConstant(Values.Objects.String.Make(digester.Previous.Value)); + } - if (canAssign && digester.Match(TokenType.Equal)) { - digester.ParseExpression(); - digester.Emit(Set); - digester.EmitDynamic(variable); - } else { - digester.Emit(Get); - digester.EmitDynamic(variable); - } - } + public static void Variable(Digester digester, string name, bool canAssign) + { + OpCode Get, Set; + long variable = digester.ResolveLocal(digester.Builder, name); + if (variable > -1) { + Get = OpCode.GetLocal; + Set = OpCode.SetLocal; + } else if ((variable = digester.ResolveOuter(digester.Builder, name)) > -1) { + Get = OpCode.GetOuter; + Set = OpCode.SetOuter; + } else { + variable = digester.IdentifierConstant(name); + Get = OpCode.GetGlobal; + Set = OpCode.SetGlobal; + } - public static void Variable(Digester digester, bool canAssign) - { - Variable(digester, digester.Previous.Value!, canAssign); - } + if (canAssign && digester.Match(TokenType.Equal)) { + digester.ParseExpression(); + digester.Emit(Set); + digester.EmitDynamic(variable); + } else { + digester.Emit(Get); + digester.EmitDynamic(variable); + } + } - static void Base(Digester digester, bool canAssign) - { - if (digester.ClassBuilder == null) - digester.ErrorAtPrevious("We're currently not in a class. 'base' only works inside of a class context."); - else if (digester.ClassBuilder.Outer == null) - digester.ErrorAtPrevious($"{digester.ClassBuilder.Name} is not inherited from any class, so the 'base' keyword points to nothing."); - else - { - digester.Consume(TokenType.Dot, "Expected '.' after 'base' keyword."); - digester.Consume(TokenType.Identifier, "Expected an identifier after 'base' keyword."); - long name = digester.IdentifierConstant(digester.Previous.Value); - Variable(digester, "this", false); - if (digester.Match(TokenType.GroupOpen)) - { - byte arguments = digester.Arguments(); - Variable(digester, "base", false); - digester.Emit(OpCode.InvokeBase); - digester.Emit(arguments); - } else { - Variable(digester, "base", false); - digester.Emit(OpCode.Base); - } - } - } + public static void Variable(Digester digester, bool canAssign) + { + Variable(digester, digester.Previous.Value!, canAssign); + } - static void This(Digester digester, bool canAssign) - { - if (digester.ClassBuilder == null) - digester.ErrorAtPrevious("We're currently not in a class. 'this' only refers to the current instance of one."); - else - Variable(digester, false); - } + static void Base(Digester digester, bool canAssign) + { + if (digester.ClassBuilder == null) + digester.ErrorAtPrevious("We're currently not in a class. 'base' only works inside of a class context."); + else if (digester.ClassBuilder.Outer == null) + digester.ErrorAtPrevious($"{digester.ClassBuilder.Name} is not inherited from any class, so the 'base' keyword points to nothing."); + else { + digester.Consume(TokenType.Dot, "Expected '.' after 'base' keyword."); + digester.Consume(TokenType.Identifier, "Expected an identifier after 'base' keyword."); + long name = digester.IdentifierConstant(digester.Previous.Value); + Variable(digester, "this", false); + if (digester.Match(TokenType.GroupOpen)) { + byte arguments = digester.Arguments(); + Variable(digester, "base", false); + digester.Emit(OpCode.InvokeBase); + digester.Emit(arguments); + } else { + Variable(digester, "base", false); + digester.Emit(OpCode.Base); + } + } + } - static void Modifier(Digester digester, bool canAssign) - { - Token token = digester.Previous; - digester.WeightedDigest(Weight.Modifier); - switch (token.Type) { - case TokenType.Bang: digester.Emit(OpCode.Not); break; - case TokenType.Minus: digester.Emit(OpCode.Negate); break; - case TokenType.BitwiseNot: digester.Emit(OpCode.BitwiseNot); break; - } - } + static void This(Digester digester, bool canAssign) + { + if (digester.ClassBuilder == null) + digester.ErrorAtPrevious("We're currently not in a class. 'this' only refers to the current instance of one."); + else + Variable(digester, false); + } - static void TypeOf(Digester digester, bool canAssign) - { - digester.TypeOf(); - } + static void Modifier(Digester digester, bool canAssign) + { + Token token = digester.Previous; + digester.WeightedDigest(Weight.Modifier); + switch (token.Type) { + case TokenType.Bang: + digester.Emit(OpCode.Not); + break; + case TokenType.Minus: + digester.Emit(OpCode.Negate); + break; + case TokenType.BitwiseNot: + digester.Emit(OpCode.BitwiseNot); + break; + } + } - static ExpressionParser() - { - _rules[TokenType.GroupOpen] = new Rule(Group, Call, Weight.Call); - _rules[TokenType.GroupClose] = new Rule(null, null, Weight.None); - _rules[TokenType.ContextOpen] = new Rule(null, null, Weight.None); - _rules[TokenType.ContextClose] = new Rule(null, null, Weight.None); - _rules[TokenType.ArrayOpen] = new Rule(Array, Accessor, Weight.Call); - _rules[TokenType.ArrayClose] = new Rule(null, null, Weight.None); - _rules[TokenType.AddItem] = new Rule(null, AddItem, Weight.None); - _rules[TokenType.RemoveItem] = new Rule(null, null, Weight.None); - _rules[TokenType.Colon] = new Rule(null, Dot, Weight.Call); - _rules[TokenType.Comma] = new Rule(null, null, Weight.None); - _rules[TokenType.Dot] = new Rule(null, Dot, Weight.Call); - _rules[TokenType.Minus] = new Rule(Modifier, Binary, Weight.Term); - _rules[TokenType.Plus] = new Rule(null, Binary, Weight.Term); - _rules[TokenType.Increment] = new Rule(Binary, Binary, Weight.Call); - _rules[TokenType.Decrement] = new Rule(Binary, Binary, Weight.Call); - _rules[TokenType.BitwiseAnd] = new Rule(Modifier, Binary, Weight.Term); - _rules[TokenType.BitwiseOr] = new Rule(null, Binary, Weight.Term); - _rules[TokenType.BitwiseXor] = new Rule(null, Binary, Weight.Term); - _rules[TokenType.BitwiseLeft] = new Rule(null, Binary, Weight.Term); - _rules[TokenType.BitwiseRight] = new Rule(null, Binary, Weight.Term); - _rules[TokenType.BitwiseNot] = new Rule(Modifier, null, Weight.Term); - _rules[TokenType.Semicolon] = new Rule(null, null, Weight.None); - _rules[TokenType.Slash] = new Rule(null, Binary, Weight.Factor); - _rules[TokenType.Star] = new Rule(null, Binary, Weight.Factor); - _rules[TokenType.Bang] = new Rule(Modifier, null, Weight.None); - _rules[TokenType.BangEqual] = new Rule(null, Binary, Weight.Equal); - _rules[TokenType.Equal] = new Rule(null, null, Weight.None); - _rules[TokenType.EqualEqual] = new Rule(null, Binary, Weight.Equal); - _rules[TokenType.Greater] = new Rule(null, Binary, Weight.Compare); - _rules[TokenType.GreaterEqual] = new Rule(null, Binary, Weight.Compare); - _rules[TokenType.Less] = new Rule(null, Binary, Weight.Compare); - _rules[TokenType.LessEqual] = new Rule(null, Binary, Weight.Compare); - _rules[TokenType.Identifier] = new Rule(Variable, null, Weight.None); - _rules[TokenType.String] = new Rule(String, null, Weight.None); - _rules[TokenType.Integer] = new Rule(Number, null, Weight.None); - _rules[TokenType.Hexadecimal] = new Rule(Number, null, Weight.None); - _rules[TokenType.Decimal] = new Rule(Number, null, Weight.None); - _rules[TokenType.And] = new Rule(null, And, Weight.And); - _rules[TokenType.Class] = new Rule(null, null, Weight.None); - _rules[TokenType.Else] = new Rule(null, null, Weight.None); - _rules[TokenType.False] = new Rule(Literal, null, Weight.None); - _rules[TokenType.For] = new Rule(null, null, Weight.None); - _rules[TokenType.Function] = new Rule(null, null, Weight.None); - _rules[TokenType.If] = new Rule(null, null, Weight.None); - _rules[TokenType.Null] = new Rule(Literal, null, Weight.None); - _rules[TokenType.Or] = new Rule(null, Or, Weight.Or); - _rules[TokenType.Print] = new Rule(null, null, Weight.None); - _rules[TokenType.TypeOf] = new Rule(TypeOf, null, Weight.None); - _rules[TokenType.Export] = new Rule(null, null, Weight.None); - _rules[TokenType.Import] = new Rule(null, null, Weight.None); - _rules[TokenType.Return] = new Rule(null, null, Weight.None); - _rules[TokenType.Base] = new Rule(Base, null, Weight.None); - _rules[TokenType.This] = new Rule(This, null, Weight.None); - _rules[TokenType.True] = new Rule(Literal, null, Weight.None); - _rules[TokenType.Var] = new Rule(null, null, Weight.None); - _rules[TokenType.While] = new Rule(null, null, Weight.None); - _rules[TokenType.Error] = new Rule(null, null, Weight.None); - _rules[TokenType.Eof] = new Rule(null, null, Weight.None); - } + static void TypeOf(Digester digester, bool canAssign) + { + digester.TypeOf(); + } + + static ExpressionParser() + { + _rules[TokenType.GroupOpen] = new Rule(Group, Call, Weight.Call); + _rules[TokenType.GroupClose] = new Rule(null, null, Weight.None); + _rules[TokenType.ContextOpen] = new Rule(null, null, Weight.None); + _rules[TokenType.ContextClose] = new Rule(null, null, Weight.None); + _rules[TokenType.ArrayOpen] = new Rule(Array, Accessor, Weight.Call); + _rules[TokenType.ArrayClose] = new Rule(null, null, Weight.None); + _rules[TokenType.AddItem] = new Rule(null, AddItem, Weight.None); + _rules[TokenType.RemoveItem] = new Rule(null, null, Weight.None); + _rules[TokenType.Colon] = new Rule(null, Dot, Weight.Call); + _rules[TokenType.Comma] = new Rule(null, null, Weight.None); + _rules[TokenType.Dot] = new Rule(null, Dot, Weight.Call); + _rules[TokenType.Minus] = new Rule(Modifier, Binary, Weight.Term); + _rules[TokenType.Plus] = new Rule(null, Binary, Weight.Term); + _rules[TokenType.Increment] = new Rule(Binary, Binary, Weight.Call); + _rules[TokenType.Decrement] = new Rule(Binary, Binary, Weight.Call); + _rules[TokenType.BitwiseAnd] = new Rule(Modifier, Binary, Weight.Term); + _rules[TokenType.BitwiseOr] = new Rule(null, Binary, Weight.Term); + _rules[TokenType.BitwiseXor] = new Rule(null, Binary, Weight.Term); + _rules[TokenType.BitwiseLeft] = new Rule(null, Binary, Weight.Term); + _rules[TokenType.BitwiseRight] = new Rule(null, Binary, Weight.Term); + _rules[TokenType.BitwiseNot] = new Rule(Modifier, null, Weight.Term); + _rules[TokenType.Semicolon] = new Rule(null, null, Weight.None); + _rules[TokenType.Slash] = new Rule(null, Binary, Weight.Factor); + _rules[TokenType.Star] = new Rule(null, Binary, Weight.Factor); + _rules[TokenType.Bang] = new Rule(Modifier, null, Weight.None); + _rules[TokenType.BangEqual] = new Rule(null, Binary, Weight.Equal); + _rules[TokenType.Equal] = new Rule(null, null, Weight.None); + _rules[TokenType.EqualEqual] = new Rule(null, Binary, Weight.Equal); + _rules[TokenType.Greater] = new Rule(null, Binary, Weight.Compare); + _rules[TokenType.GreaterEqual] = new Rule(null, Binary, Weight.Compare); + _rules[TokenType.Less] = new Rule(null, Binary, Weight.Compare); + _rules[TokenType.LessEqual] = new Rule(null, Binary, Weight.Compare); + _rules[TokenType.Identifier] = new Rule(Variable, null, Weight.None); + _rules[TokenType.String] = new Rule(String, null, Weight.None); + _rules[TokenType.Integer] = new Rule(Number, null, Weight.None); + _rules[TokenType.Hexadecimal] = new Rule(Number, null, Weight.None); + _rules[TokenType.Decimal] = new Rule(Number, null, Weight.None); + _rules[TokenType.And] = new Rule(null, And, Weight.And); + _rules[TokenType.Class] = new Rule(null, null, Weight.None); + _rules[TokenType.Else] = new Rule(null, null, Weight.None); + _rules[TokenType.False] = new Rule(Literal, null, Weight.None); + _rules[TokenType.For] = new Rule(null, null, Weight.None); + _rules[TokenType.Function] = new Rule(null, null, Weight.None); + _rules[TokenType.If] = new Rule(null, null, Weight.None); + _rules[TokenType.Null] = new Rule(Literal, null, Weight.None); + _rules[TokenType.Or] = new Rule(null, Or, Weight.Or); + _rules[TokenType.Print] = new Rule(null, null, Weight.None); + _rules[TokenType.TypeOf] = new Rule(TypeOf, null, Weight.None); + _rules[TokenType.Export] = new Rule(null, null, Weight.None); + _rules[TokenType.Import] = new Rule(null, null, Weight.None); + _rules[TokenType.Return] = new Rule(null, null, Weight.None); + _rules[TokenType.Base] = new Rule(Base, null, Weight.None); + _rules[TokenType.This] = new Rule(This, null, Weight.None); + _rules[TokenType.True] = new Rule(Literal, null, Weight.None); + _rules[TokenType.Var] = new Rule(null, null, Weight.None); + _rules[TokenType.While] = new Rule(null, null, Weight.None); + _rules[TokenType.Error] = new Rule(null, null, Weight.None); + _rules[TokenType.Eof] = new Rule(null, null, Weight.None); + } } diff --git a/Qrakhen.Qamp.Core/Compilation/Rule.cs b/Qrakhen.Qamp.Core/Compilation/Rule.cs index 3220b93..19cba5b 100644 --- a/Qrakhen.Qamp.Core/Compilation/Rule.cs +++ b/Qrakhen.Qamp.Core/Compilation/Rule.cs @@ -4,7 +4,7 @@ public delegate void RuleDelegate(Digester digester, bool canAssign); public readonly struct Rule(RuleDelegate? prefix = null, RuleDelegate? infix = null, Weight weight = Weight.None) { - public readonly RuleDelegate? Prefix = prefix; - public readonly RuleDelegate? Infix = infix; - public readonly Weight Weight = weight; + public readonly RuleDelegate? Prefix = prefix; + public readonly RuleDelegate? Infix = infix; + public readonly Weight Weight = weight; } diff --git a/Qrakhen.Qamp.Core/Compilation/Weight.cs b/Qrakhen.Qamp.Core/Compilation/Weight.cs index 9df715e..a8b94e4 100644 --- a/Qrakhen.Qamp.Core/Compilation/Weight.cs +++ b/Qrakhen.Qamp.Core/Compilation/Weight.cs @@ -2,15 +2,15 @@ public enum Weight { - None = 0, - Assign = 1, - Or = 2, - And = 3, - Equal = 4, - Compare = 5, - Term = 6, - Factor = 7, - Modifier = 8, - Call = 9, - Primary = 10 + None = 0, + Assign = 1, + Or = 2, + And = 3, + Equal = 4, + Compare = 5, + Term = 6, + Factor = 7, + Modifier = 8, + Call = 9, + Primary = 10 } diff --git a/Qrakhen.Qamp.Core/Console.cs b/Qrakhen.Qamp.Core/Console.cs index f6dfc12..0f4542b 100644 --- a/Qrakhen.Qamp.Core/Console.cs +++ b/Qrakhen.Qamp.Core/Console.cs @@ -2,11 +2,11 @@ public static class Console { - public static void Write(object? any) - { - string[] split = $"{any ?? "null"}".Split('\n'); - for (int i = 0; i < split.Length; i++) { - System.Console.Write((i == 0 ? " :> " : " ") + $"{split[i]}\n"); - } - } + public static void Write(object? any) + { + string[] split = $"{any ?? "null"}".Split('\n'); + for (int i = 0; i < split.Length; i++) { + System.Console.Write((i == 0 ? " :> " : " ") + $"{split[i]}\n"); + } + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Exceptions.cs b/Qrakhen.Qamp.Core/Exceptions.cs index 7df2fa0..aa717ce 100644 --- a/Qrakhen.Qamp.Core/Exceptions.cs +++ b/Qrakhen.Qamp.Core/Exceptions.cs @@ -4,32 +4,32 @@ using Qrakhen.Qamp.Core.Values; namespace Qrakhen.Qamp.Core; -public class QampException(string message, object? context = null) +public class QampException(string message, object? context = null) : Exception(message) { - public readonly object? Context = context; + public readonly object? Context = context; } public class ReaderException(string message, IReader reader) : QampException(message, reader.CurrentPosition) { - public readonly IReader Reader = reader; + public readonly IReader Reader = reader; } public class TokenException(string message, IReader reader, Token token) : ReaderException($"TokenError {token} at {token.Position}: {message}", reader) { - public readonly Token Token = token; + public readonly Token Token = token; } public class RuntimeException(string message, object? context = null) : QampException(message, context); public class DivisionByZeroException(string? message, object? context = null) - : RuntimeException(message ?? "Can not divide by zero", context); + : RuntimeException(message ?? "Can not divide by zero", context); public class ConversionException(string message, Value value, object? context = null) : RuntimeException(message, context) { - public readonly Value Value = value; + public readonly Value Value = value; } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Execution/Instruction.cs b/Qrakhen.Qamp.Core/Execution/Instruction.cs index 0bca50f..9e87ab2 100644 --- a/Qrakhen.Qamp.Core/Execution/Instruction.cs +++ b/Qrakhen.Qamp.Core/Execution/Instruction.cs @@ -2,15 +2,15 @@ public readonly record struct Instruction(byte Code) { - public OpCode OpCode => (OpCode)Code; + public OpCode OpCode => (OpCode)Code; - public static implicit operator byte(Instruction instruction) => instruction.Code; - public static implicit operator Instruction(byte code) => new(code); - public static implicit operator OpCode(Instruction instruction) => (OpCode)instruction.Code; - public static implicit operator Instruction(OpCode code) => new((byte)code); + public static implicit operator byte(Instruction instruction) => instruction.Code; + public static implicit operator Instruction(byte code) => new(code); + public static implicit operator OpCode(Instruction instruction) => (OpCode)instruction.Code; + public static implicit operator Instruction(OpCode code) => new((byte)code); - public override string ToString() - { - return $"<{Code:X4} | {OpCode}>"; - } + public override string ToString() + { + return $"<{Code:X4} | {OpCode}>"; + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Execution/InstructionPtr.cs b/Qrakhen.Qamp.Core/Execution/InstructionPtr.cs index 49b42e2..398d4ad 100644 --- a/Qrakhen.Qamp.Core/Execution/InstructionPtr.cs +++ b/Qrakhen.Qamp.Core/Execution/InstructionPtr.cs @@ -6,60 +6,60 @@ namespace Qrakhen.Qamp.Core.Execution; public class InstructionPtr : Pointer { - public Segment Segment; + public Segment Segment; - public Instruction Instruction => Segment.Instructions[Cursor]; + public Instruction Instruction => Segment.Instructions[Cursor]; - public InstructionPtr(Segment segment, int position = 0) : base(segment.Instructions, position) - { - Segment = segment; - } + public InstructionPtr(Segment segment, int position = 0) : base(segment.Instructions, position) + { + Segment = segment; + } - public long NextLong() - { - long value = Segment.ReadLong(Cursor); - Cursor += sizeof(long); - return value; - } + public long NextLong() + { + long value = Segment.ReadLong(Cursor); + Cursor += sizeof(long); + return value; + } - public Value NextConstant() - { - return Segment.Constants[NextDynamic()]; - } + public Value NextConstant() + { + return Segment.Constants[NextDynamic()]; + } - public String NextString() - { - Value value = NextConstant(); - if (value.IsString) - return value.Ptr.As()!; - throw new Exception($"Expected string, got {value}"); - } + public String NextString() + { + Value value = NextConstant(); + if (value.IsString) + return value.Ptr.As()!; + throw new Exception($"Expected string, got {value}"); + } - public long NextDynamic() - { - var result = Segment.ReadDynamic(Cursor, out int read); - Cursor += read; - return result; - } + public long NextDynamic() + { + var result = Segment.ReadDynamic(Cursor, out int read); + Cursor += read; + return result; + } - public String? GetStringConstant(long offset) - => Segment.Constants[offset].Ptr.Value as String; + public String? GetStringConstant(long offset) + => Segment.Constants[offset].Ptr.Value as String; - public static Instruction operator +(InstructionPtr ptr, int value) - => ptr.Segment.Instructions[ptr.Cursor + value]; + public static Instruction operator +(InstructionPtr ptr, int value) + => ptr.Segment.Instructions[ptr.Cursor + value]; - public static Instruction operator -(InstructionPtr ptr, int value) - => ptr.Segment.Instructions[ptr.Cursor - value]; + public static Instruction operator -(InstructionPtr ptr, int value) + => ptr.Segment.Instructions[ptr.Cursor - value]; - public static InstructionPtr operator ++(InstructionPtr ptr) - { - ptr.Cursor++; - return ptr; - } + public static InstructionPtr operator ++(InstructionPtr ptr) + { + ptr.Cursor++; + return ptr; + } - public static InstructionPtr operator --(InstructionPtr ptr) - { - ptr.Cursor--; - return ptr; - } + public static InstructionPtr operator --(InstructionPtr ptr) + { + ptr.Cursor--; + return ptr; + } } diff --git a/Qrakhen.Qamp.Core/Execution/Instructions.cs b/Qrakhen.Qamp.Core/Execution/Instructions.cs index f5071c6..5e92335 100644 --- a/Qrakhen.Qamp.Core/Execution/Instructions.cs +++ b/Qrakhen.Qamp.Core/Execution/Instructions.cs @@ -2,35 +2,35 @@ namespace Qrakhen.Qamp.Core.Execution; -public class Instructions(IEnumerable instructions) : +public class Instructions(IEnumerable instructions) : ISteppable, IPeekable, ISeekable { - private readonly T[] _instructions = instructions.ToArray(); + private readonly T[] _instructions = instructions.ToArray(); - public long Position { get; private set; } = 0; + public long Position { get; private set; } = 0; - public long Length => _instructions.LongLength; - public bool Done => Position >= _instructions.Length; + public long Length => _instructions.LongLength; + public bool Done => Position >= _instructions.Length; - public T this[long offset] => offset < Length ? - _instructions[offset] : - throw new ArgumentOutOfRangeException($"Tried to access offset beyond instruction length {offset}:{Length}"); + public T this[long offset] => offset < Length ? + _instructions[offset] : + throw new ArgumentOutOfRangeException($"Tried to access offset beyond instruction length {offset}:{Length}"); - public T Seek(long position) - { - Position = position; - return _instructions[Position]; - } + public T Seek(long position) + { + Position = position; + return _instructions[Position]; + } - public T Next() - { - return _instructions[Position++]; - } + public T Next() + { + return _instructions[Position++]; + } - public T Peek(int delta = 0) - { - return _instructions[Position + delta]; - } + public T Peek(int delta = 0) + { + return _instructions[Position + delta]; + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Execution/OpCode.cs b/Qrakhen.Qamp.Core/Execution/OpCode.cs index 6d19fff..4852756 100644 --- a/Qrakhen.Qamp.Core/Execution/OpCode.cs +++ b/Qrakhen.Qamp.Core/Execution/OpCode.cs @@ -2,89 +2,89 @@ public enum OpCode { - F_Mask = 0xF0, + F_Mask = 0xF0, - None = 0x00, - Constant = 0x01, - Null = 0x02, - Pop = 0x03, - Cast = 0x04, + None = 0x00, + Constant = 0x01, + Null = 0x02, + Pop = 0x03, + Cast = 0x04, - False = 0x0e, - True = 0x0f, + False = 0x0e, + True = 0x0f, - Val = 0x10, - Ref = 0x11, + Val = 0x10, + Ref = 0x11, - SetGlobal = 0x20, - GetGlobal = 0x21, - GetLocal = 0x22, - SetLocal = 0x23, - GetOuter = 0x24, - SetOuter = 0x25, - GetMember = 0x26, - SetMember = 0x27, + SetGlobal = 0x20, + GetGlobal = 0x21, + GetLocal = 0x22, + SetLocal = 0x23, + GetOuter = 0x24, + SetOuter = 0x25, + GetMember = 0x26, + SetMember = 0x27, - DefineGlobal = 0x30, - CloseOuter = 0x31, + DefineGlobal = 0x30, + CloseOuter = 0x31, - AssignValue = 0x40, // unsure - AssignReference = 0x41, // unsure + AssignValue = 0x40, // unsure + AssignReference = 0x41, // unsure - F_Operation = 0x60, - Add = 0x60, - Subtract = 0x61, - Multiply = 0x62, - Divide = 0x63, - Modulo = 0x64, - BitwiseAnd = 0x65, - BitwiseOr = 0x66, - BitwiseXor = 0x67, - BitwiseLeft = 0x68, - BitwiseRight = 0x69, - F_Unary = 0x0a, - Not = 0x6a, - Negate = 0x6b, - BitwiseNot = 0x6c, + F_Operation = 0x60, + Add = 0x60, + Subtract = 0x61, + Multiply = 0x62, + Divide = 0x63, + Modulo = 0x64, + BitwiseAnd = 0x65, + BitwiseOr = 0x66, + BitwiseXor = 0x67, + BitwiseLeft = 0x68, + BitwiseRight = 0x69, + F_Unary = 0x0a, + Not = 0x6a, + Negate = 0x6b, + BitwiseNot = 0x6c, - F_Compare = 0x50, - Equal = 0x50, - Greater = 0x51, - Less = 0x52, + F_Compare = 0x50, + Equal = 0x50, + Greater = 0x51, + Less = 0x52, - Increment = 0x70, - Decrement = 0x71, + Increment = 0x70, + Decrement = 0x71, - Array = 0xc0, - List = 0xc1, - Structure = 0xc2, - GetItem = 0xc3, - SetItem = 0xc4, - AddItem = 0xc5, - RemoveItem = 0xc6, + Array = 0xc0, + List = 0xc1, + Structure = 0xc2, + GetItem = 0xc3, + SetItem = 0xc4, + AddItem = 0xc5, + RemoveItem = 0xc6, - Return = 0x80, - Jump = 0x81, - JumpIfFalse = 0x82, - Loop = 0x83, - Invoke = 0x84, - InvokeBase = 0x85, - InvokeMember = 0x86, - Context = 0x87, + Return = 0x80, + Jump = 0x81, + JumpIfFalse = 0x82, + Loop = 0x83, + Invoke = 0x84, + InvokeBase = 0x85, + InvokeMember = 0x86, + Context = 0x87, - Class = 0xa0, - Member = 0xa1, - Base = 0xa2, - Inherit = 0xa3, - Method = 0xa4, - Static = 0xa5, + Class = 0xa0, + Member = 0xa1, + Base = 0xa2, + Inherit = 0xa3, + Method = 0xa4, + Static = 0xa5, - Print = 0xe0, - PrintStack = 0xe1, - PrintGlobals = 0xe2, - PrintExpr = 0xe3, - Typeof = 0xef, + Print = 0xe0, + PrintStack = 0xe1, + PrintGlobals = 0xe2, + PrintExpr = 0xe3, + Typeof = 0xef, - Export = 0xfe, // probably shouldnt be an op code but rather be done during digestion - Import = 0xff, // probably shouldnt be an op code but rather be done during digestion + Export = 0xfe, // probably shouldnt be an op code but rather be done during digestion + Import = 0xff, // probably shouldnt be an op code but rather be done during digestion } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Execution/Runner.cs b/Qrakhen.Qamp.Core/Execution/Runner.cs index 6b03ac7..d32cba7 100644 --- a/Qrakhen.Qamp.Core/Execution/Runner.cs +++ b/Qrakhen.Qamp.Core/Execution/Runner.cs @@ -13,631 +13,641 @@ using T = Values.ValueType; public class Call { - public Context Context; - public InstructionPtr Instruction; - public Pointer StackPtr; + public Context Context; + public InstructionPtr Instruction; + public Pointer StackPtr; - public Call(Context context, StackLike stack, long stackOffset) - { - Context = context; - Instruction = new InstructionPtr(Context.Function.Segment); - StackPtr = new Pointer(stack, stackOffset); - } + public Call(Context context, StackLike stack, long stackOffset) + { + Context = context; + Instruction = new InstructionPtr(Context.Function.Segment); + StackPtr = new Pointer(stack, stackOffset); + } } -public class Runner : IDisposable +public class Runner : IDisposable { - private readonly ILogger _logger = LoggerService.Get(); + private readonly ILogger _logger = LoggerService.Get(); - public readonly Options Options; + public readonly Options Options; - private StackLike Calls; + private StackLike Calls; - // todo: maybe have a pointer everywhere to stacks or arrays and use those rather than built-in pointers or cursors... ? - private StackLike Stack; - private long Cursor => Stack.Position; + // todo: maybe have a pointer everywhere to stacks or arrays and use those rather than built-in pointers or cursors... ? + private StackLike Stack; + private long Cursor => Stack.Position; - private List Outers = []; + private List Outers = []; - private Register Globals = new(); - private Register Imports = new(); - private Register Exports = new(); + private Register Globals = new(); + private Register Imports = new(); + private Register Exports = new(); - public Runner(Options options) - { - Options = options; - Calls = new StackLike(options.MaxCalls); - Stack = new StackLike(options.InitialStackSize); - } + public Runner(Options options) + { + Options = options; + Calls = new StackLike(options.MaxCalls); + Stack = new StackLike(options.InitialStackSize); + } - public ExecutionResult Run(Stream stream) - { + public ExecutionResult Run(Stream stream) + { #if LOG _logger.Method(); #endif - if (Stack.Position < 0) { + if (Stack.Position < 0) { #if LOG _logger.Warn($"Something went wrong, stack cursor is at {Stack.Position}. Resetting Stack."); #endif - Stack.Decimate(0); - } - using Reader reader = new Reader(stream); - Compilation.Digester digester = new(reader); - Function function = digester.Digest(); - if (stream.Length > 64) - File.WriteAllBytes($"./func.{DateTime.Now:yyyyMMdd_HHmmss}.sqi", function.Serialize(true)); - Context closure = new Context(function); - Push(Obj.Create(closure)); - Invoke(closure, 0); - return Execute(); - } + Stack = new StackLike(Options.InitialStackSize); + } + using Reader reader = new Reader(stream); + Compilation.Digester digester = new(reader); + Function function = digester.Digest(); + if (stream.Length > 64) + File.WriteAllBytes($"./func.{DateTime.Now:yyyyMMdd_HHmmss}.sqi", function.Serialize(true)); + Context closure = new Context(function); + Push(Obj.Create(closure)); + Invoke(closure, 0); + return Execute(); + } - private bool TestFlag(Op code, Op flag) => (code & Op.F_Mask) == flag; + private bool TestFlag(Op code, Op flag) => (code & Op.F_Mask) == flag; - private ExecutionResult Execute() - { + private ExecutionResult Execute() + { #if LOG _logger.Method(); #endif - Call call = Calls.Peek(-1); - do { - Op opCode = call.Instruction.Next(); + Call call = Calls.Peek(-1); + do { + Op opCode = call.Instruction.Next(); #if LOG _logger.Verbose($"OpCode: {opCode}"); #endif - if (TestFlag(opCode, Op.F_Operation)) { - Value result = ValueOperation.Resolve(PopOperation(opCode)); - Push(result); - continue; - } + if (TestFlag(opCode, Op.F_Operation)) { + Value result = ValueOperation.Resolve(PopOperation(opCode)); + Push(result); + continue; + } - if (TestFlag(opCode, Op.F_Compare)) { - Value result = ValueOperation.Resolve(PopOperation(opCode)); - Push(result); - continue; - } + if (TestFlag(opCode, Op.F_Compare)) { + Value result = ValueOperation.Resolve(PopOperation(opCode)); + Push(result); + continue; + } - switch (opCode) { - case Op.Null: Push(Value.Void); break; - case Op.Constant: Push(call.Instruction.NextConstant()); break; - case Op.Pop: Pop(); break; - case Op.True: Push(Value.True); break; - case Op.False: Push(Value.False); break; + switch (opCode) { + case Op.Null: + Push(Value.Void); + break; + case Op.Constant: + Push(call.Instruction.NextConstant()); + break; + case Op.Pop: + Pop(); + break; + case Op.True: + Push(Value.True); + break; + case Op.False: + Push(Value.False); + break; - case Op.GetGlobal: { - string? name = call.Instruction.GetStringConstant(call.Instruction.NextDynamic())?.Value; - if (string.IsNullOrEmpty(name)) - return Error($"tried to set global variable with empty name"); - if (!Globals.Has(name)) - Push(Value.Void); - else - Push(Globals[name]); + case Op.GetGlobal: { + string? name = call.Instruction.GetStringConstant(call.Instruction.NextDynamic())?.Value; + if (string.IsNullOrEmpty(name)) + return Error($"tried to set global variable with empty name"); + if (!Globals.Has(name)) + Push(Value.Void); + else + Push(Globals[name]); #if LOG _logger.Verbose($"got global {name} ({Peek()})"); #endif - break; - } + break; + } - case Op.SetGlobal: { - string? name = call.Instruction.GetStringConstant(call.Instruction.NextDynamic())?.Value; - if (string.IsNullOrEmpty(name)) - return Error($"tried to set global variable with empty name"); - if (!Globals.Has(name)) - return Error($"tried to set a value of non-existing global variable"); - Globals[name] = Pop(); + case Op.SetGlobal: { + string? name = call.Instruction.GetStringConstant(call.Instruction.NextDynamic())?.Value; + if (string.IsNullOrEmpty(name)) + return Error($"tried to set global variable with empty name"); + if (!Globals.Has(name)) + return Error($"tried to set a value of non-existing global variable"); + Globals[name] = Pop(); #if LOG _logger.Verbose($"set global {name} = {Globals[name]}"); #endif - break; - } + break; + } - case Op.DefineGlobal: { - string? name = call.Instruction.GetStringConstant(call.Instruction.NextDynamic())?.Value; - if (string.IsNullOrEmpty(name)) - return Error($"tried to define global variable with empty name"); - Globals[name] = Pop(); + case Op.DefineGlobal: { + string? name = call.Instruction.GetStringConstant(call.Instruction.NextDynamic())?.Value; + if (string.IsNullOrEmpty(name)) + return Error($"tried to define global variable with empty name"); + Globals[name] = Pop(); #if LOG _logger.Verbose($"defined global {name} as {Globals[name]}"); #endif - break; - } + break; + } - case Op.GetLocal: { - long slot = call.Instruction.NextDynamic(); + case Op.GetLocal: { + long slot = call.Instruction.NextDynamic(); #if LOG _logger.Verbose($"getting slot {slot} which is {call.StackPtr.Get(slot)}"); #endif - Push(call.StackPtr.Get(slot)); - break; - } + Push(call.StackPtr.Get(slot)); + break; + } - case Op.SetLocal: { - long slot = call.Instruction.NextDynamic(); + case Op.SetLocal: { + long slot = call.Instruction.NextDynamic(); #if LOG _logger.Verbose($"setting stackptr {slot} to {Peek()}"); #endif - call.StackPtr.Set(slot, Peek()); - break; - } - - case Op.GetOuter: { - long slot = call.Instruction.NextDynamic(); - Push(call.Context.Outers[slot].Value); - break; - } - - case Op.SetOuter: { - long slot = call.Instruction.NextDynamic(); - call.Context.Outers[slot].Value = Peek(); - break; - } - - case Op.GetMember: { - Value value = Peek(); - if (!value.Is(T.Instance)) - return Error("Only instances have members."); - Instance instance = value.Ptr.As()!; - string name = call.Instruction.NextString().Value!; - if (instance.Values.TryGet(name, out Value member)) { - Pop(); // remove instance from stack - Push(member); - } else if (!BindMethod(instance.Class, name)) { - return Error($"Could not bind member {name} to instance {instance} of class {instance.Class.Name}!"); - } - - break; - } - - case Op.SetMember: { - Value value = Peek(-2); - if (!value.Is(T.Instance)) - return Error("Only instances have members."); - Instance instance = value.Ptr.As()!; - string name = call.Instruction.NextString().Value!; - instance.Values.Set(name, Peek()); - Value move = Pop(); - Pop(); // remove instance from stack - Push(move); - break; - } - - case Op.Base: { - string name = call.Instruction.NextString().Value!; - Class @class = Pop().Ptr.As()!; - if (!BindMethod(@class, name)) - return Error($"Could not bind member {name} to base class {@class.Name}"); - break; - } - - case Op.Array: { - int length = (int)call.Instruction.NextDynamic(); - Value[] values = new Value[length]; - for (int i = length - 1; i >= 0; i--) { - values[i] = Pop(); - } - var array = new Values.Objects.Array(values); - Value value = Obj.Create(array); - Push(value); - break; - } - - case Op.GetItem: { - Value index = Pop(); - Value items = Pop(); - if (!items.Is(T.ItemProvider, false)) - return Error($"Can not access {index} of {items} - it is not an ItemProvider! (Array, List, etc.)"); - - if (items.Is(T.Array)) - Push(items.Ptr.As()!.Get(index)); - else if (items.Is(T.List)) - Push(items.Ptr.As()!.Get(index)); - else if (items.Is(T.Structure)) - Push(items.Ptr.As()!.Get(index)); - else - return Error($"Unsupported native accessor for type {items.Type}!"); - break; - } - - case Op.SetItem: { - Value value = Pop(); - Value index = Pop(); - Value items = Pop(); - if (!items.Is(T.ItemProvider, false)) - return Error($"Can not access {index} of {items} - it is not an ItemProvider! (Array, List, etc.)"); - - if (items.Is(T.Array)) - items.Ptr.As()!.Set(index, value); - else if (items.Is(T.List)) - items.Ptr.As()!.Set(index, value); - else if (items.Is(T.Structure)) - items.Ptr.As()!.Set(index, value); - else - return Error($"Unsupported native accessor for type {items.Type}!"); - break; - } - - case Op.AddItem: { - Value value = Pop(); - Value items = Pop(); - if (!items.Is(T.List)) - return Error($"Can not add {value} to {items} - only lists :[] support the native add <+ operator."); - - items.Ptr.As()!.Add(value); - break; - } - - case Op.Jump: { - long delta = call.Instruction.NextLong(); - call.Instruction.Cursor += delta; - break; - } - - case Op.JumpIfFalse: { - long delta = call.Instruction.NextLong(); - if (Peek().IsFalsy) - call.Instruction.Cursor += delta; - break; - } - - case Op.Loop: { - long delta = call.Instruction.NextLong(); - call.Instruction.Cursor -= delta; - break; - } - - case Op.Invoke: { - byte count = call.Instruction.Next(); - if (!Invoke(Peek(-(count + 1)), count)) - return Error($"Could not invoke function."); - call = Calls.Peek(); - break; - } - - case Op.InvokeMember: { - string name = call.Instruction.NextString().Value!; - byte argumentCount = call.Instruction.Next(); - if (!Invoke(name, argumentCount)) - return Error($"Could not invoke member {name}."); - call = Calls.Peek(); - break; - } - - case Op.InvokeBase: { - string name = call.Instruction.NextString().Value!; - byte argumentCount = call.Instruction.Next(); - Class @class = Pop().Ptr.As()!; - if (!Invoke(@class, name, argumentCount)) - return Error($"Could not invoke member {name} of base class {@class.Name}!"); - call = Calls.Peek(); - break; - } - - case Op.Context: { - Function function = call.Instruction.NextConstant().Ptr.As()!; - Context context = new Context(function); - Push(Obj.Create(context)); - for (int i = 0; i < context.Function.OuterCount; i++) { - Outer outer = context.Outers[i]; - bool isLocal = call.Instruction.Next() == 1; - long index = call.Instruction.NextDynamic(); - if (isLocal) - context.Outers.Add(CaptureOuter(call.StackPtr.Branch(index))); - else - context.Outers.Add(call.Context.Outers[index]); - } - break; - } - - case Op.CloseOuter: { - CloseOuters(new Pointer(Stack, Cursor)); - Pop(); - break; - } - - case Op.Return: { - Value result = Pop(); - CloseOuters(call.StackPtr.Branch()); - Calls.Pop(); - if (Calls.Count == 0) { - Pop(); - return ExecutionResult.OK; - } - Stack.Decimate(call.StackPtr.Cursor); - Push(result); - call = Calls.Peek(); - break; - } - - case Op.Class: { - Push(Obj.Create(new Class(call.Instruction.NextString().Value!))); - break; - } - - case Op.Inherit: { - Value @class = Peek(-2); - if (!@class.Is(T.Class)) - return Error($"Can not inherit from {@class}, value must be of type Class."); - Class baseClass = @class.Ptr.As()!; - Class inheritingClass = Peek().Ptr.As()!; - foreach (var member in baseClass.Members) { - if (!inheritingClass.Members.Has(member.Key)) - inheritingClass.Members.Add(member.Key, member.Value); - } - Pop(); - break; - } - - case Op.Method: - DefineMember(call.Instruction.NextString().Value!); - break; - - case Op.Typeof: { - Value value = Pop(); - string type; - if (value.Is(T.Class)) - type = value.Ptr.As()!.Name; - else if (value.Is(T.Instance)) - type = $"instance of {value.Ptr.As()!.Class.Name}"; - else if (value.Is(T.Function)) - type = $"function {value.Ptr.As()!.Name}"; - else if (value.Is(T.Method)) - type = $"method {value.Ptr.As()!.Function.Name}"; - else - type = value.Type.ToString(); - Push(String.Make(type)); - break; - } - - case Op.Print: { - Value value = Pop(); - IO.Console.Write(value); - break; - } - - case Op.PrintStack: { - for (int i = 0; i < Cursor; i++) { - IO.Console.Write($"{Stack[i].ToString(true)}"); - } - break; - } - - case Op.PrintGlobals: { - foreach (var value in Globals) { - IO.Console.Write($"{value.Key}: {value.Value.ToString(true)}"); - } - break; - } - - default: - return Error($"Unexpected or not yet supported OpCode {opCode}!"); + call.StackPtr.Set(slot, Peek()); + break; } - } while (call.Instruction.Segment.Instructions.Length > call.Instruction.Cursor); - - return ExecutionResult.OK; - } + case Op.GetOuter: { + long slot = call.Instruction.NextDynamic(); + Push(call.Context.Outers[slot].Value); + break; + } - private Outer CaptureOuter(Pointer target) - { - Outer? outer = null; - for (int i = Outers.Count; i-->0;) { - outer = Outers[i]; - if (outer.Target.Cursor <= target.Cursor) - break; - } + case Op.SetOuter: { + long slot = call.Instruction.NextDynamic(); + call.Context.Outers[slot].Value = Peek(); + break; + } - if (outer != null && outer.Target.Cursor == target.Cursor) - return outer; + case Op.GetMember: { + Value value = Peek(); + if (!value.Is(T.Instance)) + return Error("Only instances have members."); + Instance instance = value.Ptr.As()!; + string name = call.Instruction.NextString().Value!; + if (instance.Values.TryGet(name, out Value member)) { + Pop(); // remove instance from stack + Push(member); + } else if (!BindMethod(instance.Class, name)) { + return Error($"Could not bind member {name} to instance {instance} of class {instance.Class.Name}!"); + } - return new Outer(target); - } + break; + } - private void CloseOuters(Pointer last) - { - for (int i = Outers.Count;i-->0;) { - Outer outer = Outers[i]; - if (outer.IsClosed) - continue; - if (outer.Target.Cursor < last.Cursor) - return; - outer.Close(); - } - } + case Op.SetMember: { + Value value = Peek(-2); + if (!value.Is(T.Instance)) + return Error("Only instances have members."); + Instance instance = value.Ptr.As()!; + string name = call.Instruction.NextString().Value!; + instance.Values.Set(name, Peek()); + Value move = Pop(); + Pop(); // remove instance from stack + Push(move); + break; + } - private bool InvokeNative(Value target, NativeExtension extension, int argumentCount) - { + case Op.Base: { + string name = call.Instruction.NextString().Value!; + Class @class = Pop().Ptr.As()!; + if (!BindMethod(@class, name)) + return Error($"Could not bind member {name} to base class {@class.Name}"); + break; + } + + case Op.Array: { + int length = (int)call.Instruction.NextDynamic(); + Value[] values = new Value[length]; + for (int i = length - 1; i >= 0; i--) { + values[i] = Pop(); + } + var array = new Values.Objects.Array(values); + Value value = Obj.Create(array); + Push(value); + break; + } + + case Op.GetItem: { + Value index = Pop(); + Value items = Pop(); + if (!items.Is(T.ItemProvider, false)) + return Error($"Can not access {index} of {items} - it is not an ItemProvider! (Array, List, etc.)"); + + if (items.Is(T.Array)) + Push(items.Ptr.As()!.Get(index)); + else if (items.Is(T.List)) + Push(items.Ptr.As()!.Get(index)); + else if (items.Is(T.Structure)) + Push(items.Ptr.As()!.Get(index)); + else + return Error($"Unsupported native accessor for type {items.Type}!"); + break; + } + + case Op.SetItem: { + Value value = Pop(); + Value index = Pop(); + Value items = Pop(); + if (!items.Is(T.ItemProvider, false)) + return Error($"Can not access {index} of {items} - it is not an ItemProvider! (Array, List, etc.)"); + + if (items.Is(T.Array)) + items.Ptr.As()!.Set(index, value); + else if (items.Is(T.List)) + items.Ptr.As()!.Set(index, value); + else if (items.Is(T.Structure)) + items.Ptr.As()!.Set(index, value); + else + return Error($"Unsupported native accessor for type {items.Type}!"); + break; + } + + case Op.AddItem: { + Value value = Pop(); + Value items = Pop(); + if (!items.Is(T.List)) + return Error($"Can not add {value} to {items} - only lists :[] support the native add <+ operator."); + + items.Ptr.As()!.Add(value); + break; + } + + case Op.Jump: { + long delta = call.Instruction.NextLong(); + call.Instruction.Cursor += delta; + break; + } + + case Op.JumpIfFalse: { + long delta = call.Instruction.NextLong(); + if (Peek().IsFalsy) + call.Instruction.Cursor += delta; + break; + } + + case Op.Loop: { + long delta = call.Instruction.NextLong(); + call.Instruction.Cursor -= delta; + break; + } + + case Op.Invoke: { + byte count = call.Instruction.Next(); + if (!Invoke(Peek(-(count + 1)), count)) + return Error($"Could not invoke function."); + call = Calls.Peek(); + break; + } + + case Op.InvokeMember: { + string name = call.Instruction.NextString().Value!; + byte argumentCount = call.Instruction.Next(); + if (!Invoke(name, argumentCount)) + return Error($"Could not invoke member {name}."); + call = Calls.Peek(); + break; + } + + case Op.InvokeBase: { + string name = call.Instruction.NextString().Value!; + byte argumentCount = call.Instruction.Next(); + Class @class = Pop().Ptr.As()!; + if (!Invoke(@class, name, argumentCount)) + return Error($"Could not invoke member {name} of base class {@class.Name}!"); + call = Calls.Peek(); + break; + } + + case Op.Context: { + Function function = call.Instruction.NextConstant().Ptr.As()!; + Context context = new Context(function); + Push(Obj.Create(context)); + for (int i = 0; i < context.Function.OuterCount; i++) { + Outer outer = context.Outers[i]; + bool isLocal = call.Instruction.Next() == 1; + long index = call.Instruction.NextDynamic(); + if (isLocal) + context.Outers.Add(CaptureOuter(call.StackPtr.Branch(index))); + else + context.Outers.Add(call.Context.Outers[index]); + } + break; + } + + case Op.CloseOuter: { + CloseOuters(new Pointer(Stack, Cursor)); + Pop(); + break; + } + + case Op.Return: { + Value result = Pop(); + CloseOuters(call.StackPtr.Branch()); + Calls.Pop(); + if (Calls.Count == 0) { + Pop(); + return ExecutionResult.OK; + } + Stack.Decimate(call.StackPtr.Cursor); + Push(result); + call = Calls.Peek(); + break; + } + + case Op.Class: { + Push(Obj.Create(new Class(call.Instruction.NextString().Value!))); + break; + } + + case Op.Inherit: { + Value @class = Peek(-2); + if (!@class.Is(T.Class)) + return Error($"Can not inherit from {@class}, value must be of type Class."); + Class baseClass = @class.Ptr.As()!; + Class inheritingClass = Peek().Ptr.As()!; + foreach (var member in baseClass.Members) { + if (!inheritingClass.Members.Has(member.Key)) + inheritingClass.Members.Add(member.Key, member.Value); + } + Pop(); + break; + } + + case Op.Method: + DefineMember(call.Instruction.NextString().Value!); + break; + + case Op.Typeof: { + Value value = Pop(); + string type; + if (value.Is(T.Class)) + type = value.Ptr.As()!.Name; + else if (value.Is(T.Instance)) + type = $"instance of {value.Ptr.As()!.Class.Name}"; + else if (value.Is(T.Function)) + type = $"function {value.Ptr.As()!.Name}"; + else if (value.Is(T.Method)) + type = $"method {value.Ptr.As()!.Function.Name}"; + else + type = value.Type.ToString(); + Push(String.Make(type)); + break; + } + + case Op.Print: { + Value value = Pop(); + IO.Console.Write(value); + break; + } + + case Op.PrintStack: { + for (int i = 0; i < Cursor; i++) { + IO.Console.Write($"{Stack[i].ToString(true)}"); + } + break; + } + + case Op.PrintGlobals: { + foreach (var value in Globals) { + IO.Console.Write($"{value.Key}: {value.Value.ToString(true)}"); + } + break; + } + + default: + return Error($"Unexpected or not yet supported OpCode {opCode}!"); + } + + } while (call.Instruction.Segment.Instructions.Length > call.Instruction.Cursor); + + return ExecutionResult.OK; + } + + private Outer CaptureOuter(Pointer target) + { + Outer? outer = null; + for (int i = Outers.Count; i-- > 0;) { + outer = Outers[i]; + if (outer.Target.Cursor <= target.Cursor) + break; + } + + if (outer != null && outer.Target.Cursor == target.Cursor) + return outer; + + return new Outer(target); + } + + private void CloseOuters(Pointer last) + { + for (int i = Outers.Count; i-- > 0;) { + Outer outer = Outers[i]; + if (outer.IsClosed) + continue; + if (outer.Target.Cursor < last.Cursor) + return; + outer.Close(); + } + } + + private bool InvokeNative(Value target, NativeExtension extension, int argumentCount) + { #if LOG _logger.Method(extension); #endif - if (argumentCount != extension.Parameters.Length) { - Error($"{extension} expects {extension.Parameters.Length} arguments, received {argumentCount}"); - return false; - } + if (argumentCount != extension.Parameters.Length) { + Error($"{extension} expects {extension.Parameters.Length} arguments, received {argumentCount}"); + return false; + } - var values = new Value[argumentCount]; - for (int i = 0; i < argumentCount; i++) { - values[i] = Peek(-i - 1); - } + var values = new Value[argumentCount]; + for (int i = 0; i < argumentCount; i++) { + values[i] = Peek(-i - 1); + } - Stack.Decimate(Stack.Position - argumentCount - 1); - Value result = extension.Callback(target, values); - Push(result); - return true; - } + Stack.Decimate(Stack.Position - argumentCount - 1); + Value result = extension.Callback(target, values); + Push(result); + return true; + } - private bool Invoke(Context closure, int argumentCount) - { + private bool Invoke(Context closure, int argumentCount) + { #if LOG _logger.Method(); #endif - if (argumentCount != closure.Function.ArgumentCount) { - Error($"Expected {closure.Function.ArgumentCount} arguments but got {argumentCount}"); + if (argumentCount != closure.Function.ArgumentCount) { + Error($"Expected {closure.Function.ArgumentCount} arguments but got {argumentCount}"); + return false; + } + + if (Calls.Count > Options.MaxCalls) { + Error($"Stack overflow {Calls.Count}"); + return false; + } + + Call call = new(closure, Stack, Cursor - argumentCount - 1); + Calls.Push(call); + return true; + } + + private bool Invoke(string methodName, int argumentCount) + { + Value value = Peek(-argumentCount - 1); + if (!value.Is(T.Instance)) { + NativeExtension? extension = NativeExtension.Get(value.Type, methodName); + if (extension == null) { + Error($"Could not invoke {methodName} on {value}, no method or extension by that name found for this type."); return false; - } + } + return InvokeNative(value, extension, argumentCount); + } - if (Calls.Count > Options.MaxCalls) { - Error($"Stack overflow {Calls.Count}"); + Instance instance = value.Ptr.As()!; + if (instance.Values.TryGet(methodName, out Value method)) + return Invoke(method, argumentCount); + + return Invoke(instance.Class, methodName, argumentCount); + } + + private bool Invoke(Class @class, string methodName, int argumentCount) + { + if (@class.Members.TryGet(methodName, out Value method)) + return Invoke(method, argumentCount); + Error($"Could not call method {methodName} on class {@class.Name}: Member does not exist"); + return false; + } + + private bool Invoke(Value value, int argumentCount) + { + if (!value.IsObj) { + Error($"Can only call values of object type! Tried to call {value.ToString(true)}", value); + return false; + } + + if (value.Is(T.Method)) { + Method method = value.Ptr.As()!; + Stack.Set(Cursor - method.Function.ArgumentCount - 1, method.Receiver); + return Invoke(method, method.Function.ArgumentCount); + } else if (value.Is(T.Context)) { + Context? context = value.Ptr.As()!; + return Invoke(context, context.Function.ArgumentCount); + } else if (value.Is(T.Native)) { + throw new NotImplementedException("i dont really want globals in this language so lets see"); + } else if (value.Is(T.Class)) { + Class? @class = value.Ptr.As()!; + Stack.Set(Cursor - argumentCount - 1, Instantiate(@class)); + if (@class.Members.TryGet(@class.Name, out Value ctor)) { + Context? context = ctor.Ptr.As()!; + return Invoke(context, argumentCount); + } else if (argumentCount != 0) { + Error($"{@class.Name}() expects 0 arguments but received {argumentCount}"); return false; - } + } + } else { + return false; + } - Call call = new(closure, Stack, Cursor - argumentCount - 1); - Calls.Push(call); - return true; - } + return true; + } - private bool Invoke(string methodName, int argumentCount) - { - Value value = Peek(-argumentCount - 1); - if (!value.Is(T.Instance)) { - NativeExtension? extension = NativeExtension.Get(value.Type, methodName); - if (extension == null) { - Error($"Could not invoke {methodName} on {value}, no method or extension by that name found for this type."); - return false; - } - return InvokeNative(value, extension, argumentCount); - } + private bool BindMethod(Class @class, string name) + { + if (!@class.Members.TryGet(name, out Value value)) { + Error($"Undefined member '{name}' on class {@class.Name}"); + return false; + } - Instance instance = value.Ptr.As()!; - if (instance.Values.TryGet(methodName, out Value method)) - return Invoke(method, argumentCount); - - return Invoke(instance.Class, methodName, argumentCount); - } + Method method = new Method(value.Ptr.As()!.Function, Peek()); + Pop(); // remove instance from stack + Push(Obj.Create(method)); + return true; + } - private bool Invoke(Class @class, string methodName, int argumentCount) - { - if (@class.Members.TryGet(methodName, out Value method)) - return Invoke(method, argumentCount); - Error($"Could not call method {methodName} on class {@class.Name}: Member does not exist"); - return false; - } + private Value Instantiate(Class @class) + { + Instance instance = new Instance(@class); + // todo: init fields etc here too + return Obj.Create(instance); + } - private bool Invoke(Value value, int argumentCount) - { - if (!value.IsObj) { - Error($"Can only call values of object type! Tried to call {value.ToString(true)}", value); - return false; - } + private void DefineMember(string name) + { + Value method = Peek(); + Class @class = Peek(-2).Ptr.As()!; + @class.Members.Set(name, method); + Pop(); + } - if (value.Is(T.Method)) { - Method method = value.Ptr.As()!; - Stack.Set(Cursor - method.Function.ArgumentCount - 1, method.Receiver); - return Invoke(method, method.Function.ArgumentCount); - } else if (value.Is(T.Context)) { - Context? context = value.Ptr.As()!; - return Invoke(context, context.Function.ArgumentCount); - } else if (value.Is(T.Native)) { - throw new NotImplementedException("i dont really want globals in this language so lets see"); - } else if (value.Is(T.Class)) { - Class? @class = value.Ptr.As()!; - Stack.Set(Cursor - argumentCount - 1, Instantiate(@class)); - if (@class.Members.TryGet(@class.Name, out Value ctor)) { - Context? context = ctor.Ptr.As()!; - return Invoke(context, argumentCount); - } else if (argumentCount != 0) { - Error($"{@class.Name}() expects 0 arguments but received {argumentCount}"); - return false; - } - } else { - return false; - } - - return true; - } - - private bool BindMethod(Class @class, string name) - { - if (!@class.Members.TryGet(name, out Value value)) { - Error($"Undefined member '{name}' on class {@class.Name}"); - return false; - } - - Method method = new Method(value.Ptr.As()!.Function, Peek()); - Pop(); // remove instance from stack - Push(Obj.Create(method)); - return true; - } - - private Value Instantiate(Class @class) - { - Instance instance = new Instance(@class); - // todo: init fields etc here too - return Obj.Create(instance); - } - - private void DefineMember(string name) - { - Value method = Peek(); - Class @class = Peek(-2).Ptr.As()!; - @class.Members.Set(name, method); - Pop(); - } - - private Value Peek(int delta = -1) - { + private Value Peek(int delta = -1) + { #if LOG _logger.Method(); #endif - return Stack.Peek(delta); - } + return Stack.Peek(delta); + } - private Value Pop() - { + private Value Pop() + { #if LOG _logger.Method(); #endif - return Stack.Pop(); - } + return Stack.Pop(); + } - private void Push(Value value) - { + private void Push(Value value) + { #if LOG _logger.Method($"{value}"); #endif - Stack.Push(value); - } + Stack.Push(value); + } - private Operation PopOperation(Op code) - { + private Operation PopOperation(Op code) + { #if LOG _logger.Method(code); #endif - if ((code & Op.F_Unary) == Op.F_Unary) - return new Operation(code, Pop(), default); - Value right = Pop(); - Value left = Pop(); - return new Operation(code, left, right); - } + if ((code & Op.F_Unary) == Op.F_Unary) + return new Operation(code, Pop(), default); + Value right = Pop(); + Value left = Pop(); + return new Operation(code, left, right); + } - private ExecutionResult Error(string message, object? context = null, bool @throw = true) - { + private ExecutionResult Error(string message, object? context = null, bool @throw = true) + { #if LOG _logger.Method(message); #endif #if LOG _logger.Error(message, context); #endif - Panic(); - if (@throw) - throw new QampException(message, context); - return ExecutionResult.Execution; - } + Panic(); + if (@throw) + throw new QampException(message, context); + return ExecutionResult.Execution; + } - private void Panic() - { + private void Panic() + { #if LOG _logger.Method(); #endif - Stack.Decimate(0); - } + Stack.Decimate(0); + } - public void Dispose() - { + public void Dispose() + { #if LOG _logger.Method(); #endif - } + } } public class GarbageCollector @@ -647,10 +657,10 @@ public class GarbageCollector public enum ExecutionResult { - OK = 0x0000, - Error = 0x1000, - Compilation = Error | 0x0001, - Execution = Error | 0x0002 + OK = 0x0000, + Error = 0x1000, + Compilation = Error | 0x0001, + Execution = Error | 0x0002 } public readonly struct Options( @@ -658,9 +668,9 @@ public readonly struct Options( int stackSize = 0x200, int initialStackSize = 0x80) { - public readonly int MaxCalls = maxCalls; - public readonly int StackSize = stackSize; - public readonly int InitialStackSize = initialStackSize; + public readonly int MaxCalls = maxCalls; + public readonly int StackSize = stackSize; + public readonly int InitialStackSize = initialStackSize; - public Options() : this(0x100, 0x200, 0x80) { } + public Options() : this(0x100, 0x200, 0x80) { } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Execution/Segment.cs b/Qrakhen.Qamp.Core/Execution/Segment.cs index 6922f5f..bde6ab2 100644 --- a/Qrakhen.Qamp.Core/Execution/Segment.cs +++ b/Qrakhen.Qamp.Core/Execution/Segment.cs @@ -5,81 +5,81 @@ using Qrakhen.Qamp.Core.Values.Objects; namespace Qrakhen.Qamp.Core.Execution; -using Unsigned = ulong; -using Signed = long; -using Char = char; -using Byte = byte; -using Bool = bool; -using Decimal = double; +using Unsigned = ulong; +using Signed = long; +using Char = char; +using Byte = byte; +using Bool = bool; +using Decimal = double; public class Segment( IEnumerable instructions, IEnumerable constants) : ISerialize { - public readonly FixedArray Instructions = new(instructions); - public readonly FixedArray Constants = new(constants); - - public byte Read(long offset) => Instructions[offset]; + public readonly FixedArray Instructions = new(instructions); + public readonly FixedArray Constants = new(constants); - public byte[] Read(long offset, int length) - { - ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + length, Instructions.Length); - byte[] bytes = new byte[length]; - for (int i = 0; i < length; i++) - bytes[i] = Instructions[offset + i]; - return bytes; - } + public byte Read(long offset) => Instructions[offset]; - /// - /// Although this always returns a long, the actually stored data in the instruction set has a dynamic width - /// (anything between 1 and 9 bytes, 1 if it's just a byte, and 1 + n, where n is up to 8 bytes).
- /// If the first byte read is masked with 0x80, it means that this byte represents the amount of bytes that - /// shall be read. If it is not, the byte is returned directly (for smaller offsets). - ///
- /// - /// All of this is done to compress compiled instruction size. - /// Todo: It will need to be tested wheter the cost on performance is stronger than anticipated. - /// - public long ReadDynamic(long offset, out int read) - { - byte value = Read(offset); - read = 1; - if (value < 0x80) // 0x80 flag for length, less than 0x80 means direct read - return value; - int length = value ^ 0x80; - read += length; - var data = new byte[8]; - for (int i = 0; i < length; i++) - data[i] = Read(offset + i); - return data.ToInt64(); - } + public byte[] Read(long offset, int length) + { + ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + length, Instructions.Length); + byte[] bytes = new byte[length]; + for (int i = 0; i < length; i++) + bytes[i] = Instructions[offset + i]; + return bytes; + } - public short ReadShort(long offset) => BitConverter.ToInt16(Read(offset, 2)); - public int ReadInt(long offset) => BitConverter.ToInt32(Read(offset, 4)); - public long ReadLong(long offset) => BitConverter.ToInt64(Read(offset, 8)); + /// + /// Although this always returns a long, the actually stored data in the instruction set has a dynamic width + /// (anything between 1 and 9 bytes, 1 if it's just a byte, and 1 + n, where n is up to 8 bytes).
+ /// If the first byte read is masked with 0x80, it means that this byte represents the amount of bytes that + /// shall be read. If it is not, the byte is returned directly (for smaller offsets). + ///
+ /// + /// All of this is done to compress compiled instruction size. + /// Todo: It will need to be tested wheter the cost on performance is stronger than anticipated. + /// + public long ReadDynamic(long offset, out int read) + { + byte value = Read(offset); + read = 1; + if (value < 0x80) // 0x80 flag for length, less than 0x80 means direct read + return value; + int length = value ^ 0x80; + read += length; + var data = new byte[8]; + for (int i = 0; i < length; i++) + data[i] = Read(offset + i); + return data.ToInt64(); + } - public byte[] Serialize() - { - var opCodes = Instructions.Select(i => (byte)i).ToArray(); - var constants = Constants.ToArray(); - byte[] bytes = new byte[sizeof(long) + opCodes.Length]; - System.Array.Copy(opCodes.LongLength.GetBytes(), 0, bytes, 0, sizeof(long)); - System.Array.Copy(opCodes, 0, bytes, sizeof(long), opCodes.Length); - var list = new List(bytes); - foreach (var constant in constants) { - var data = constant.Signed.GetDynamicBytes(); - if (data.Length == 1) - list.Add(data[0]); - else { - list.Add((byte)(data.Length | 0x80)); - list.AddRange(data); - } - } - return list.ToArray(); - } + public short ReadShort(long offset) => BitConverter.ToInt16(Read(offset, 2)); + public int ReadInt(long offset) => BitConverter.ToInt32(Read(offset, 4)); + public long ReadLong(long offset) => BitConverter.ToInt64(Read(offset, 8)); - public static Segment Deserialize(byte[] data) - { - return null; - } + public byte[] Serialize() + { + var opCodes = Instructions.Select(i => (byte)i).ToArray(); + var constants = Constants.ToArray(); + byte[] bytes = new byte[sizeof(long) + opCodes.Length]; + System.Array.Copy(opCodes.LongLength.GetBytes(), 0, bytes, 0, sizeof(long)); + System.Array.Copy(opCodes, 0, bytes, sizeof(long), opCodes.Length); + var list = new List(bytes); + foreach (var constant in constants) { + var data = constant.Signed.GetDynamicBytes(); + if (data.Length == 1) + list.Add(data[0]); + else { + list.Add((byte)(data.Length | 0x80)); + list.AddRange(data); + } + } + return list.ToArray(); + } + + public static Segment Deserialize(byte[] data) + { + return null; + } } diff --git a/Qrakhen.Qamp.Core/Execution/ValueOperation.cs b/Qrakhen.Qamp.Core/Execution/ValueOperation.cs index 90ccb5c..7f52389 100644 --- a/Qrakhen.Qamp.Core/Execution/ValueOperation.cs +++ b/Qrakhen.Qamp.Core/Execution/ValueOperation.cs @@ -19,7 +19,6 @@ public static class ValueOperation #if LOG _logger.Method($"{operation.Left} {operation.OpCode} {operation.Right}"); #endif - // p sure switch is faster here (as opposed to dict lookup) return operation.OpCode switch { OpCode.Equal => Equal(operation), @@ -94,9 +93,6 @@ public static class ValueOperation public static Value Not(Operation operation) { Value value = operation.Left; -#if LOG - _logger.Method($"{value}"); -#endif Assert.NotVoid(value); ulong inner = value.Unsigned; return new Value(inner == 0); diff --git a/Qrakhen.Qamp.Core/Extensions.cs b/Qrakhen.Qamp.Core/Extensions.cs index f3b1422..4d78c8a 100644 --- a/Qrakhen.Qamp.Core/Extensions.cs +++ b/Qrakhen.Qamp.Core/Extensions.cs @@ -5,97 +5,97 @@ namespace Qrakhen.Qamp.Core; public static class Extensions { - public static uint GetHash(this string str) - { - if (string.IsNullOrEmpty(str)) - return 0; + public static uint GetHash(this string str) + { + if (string.IsNullOrEmpty(str)) + return 0; - byte[] bytes = Encoding.ASCII.GetBytes(str); - unchecked { - uint hash = 216613661u; - for (int i = 0; i < bytes.Length; i++) { - hash ^= bytes[i]; - hash *= 16777619; - } - return hash; - } - } + byte[] bytes = Encoding.ASCII.GetBytes(str); + unchecked { + uint hash = 216613661u; + for (int i = 0; i < bytes.Length; i++) { + hash ^= bytes[i]; + hash *= 16777619; + } + return hash; + } + } - public static bool TryMatch(this Regex regex, string str, out Match match) - { - match = regex.Match(str); - return match.Success; - } + public static bool TryMatch(this Regex regex, string str, out Match match) + { + match = regex.Match(str); + return match.Success; + } - public static T[] Subset(this T[] array, long from, long length) - { - var result = new T[length]; - Array.Copy(array, from, result, 0, length); - return result; - } + public static T[] Subset(this T[] array, long from, long length) + { + var result = new T[length]; + Array.Copy(array, from, result, 0, length); + return result; + } - /// - /// Expensive. - /// - public static void Insert(this Stream stream, byte[] data, long position = -1) - { - if (position < 0) - position = stream.Position; + /// + /// Expensive. + /// + public static void Insert(this Stream stream, byte[] data, long position = -1) + { + if (position < 0) + position = stream.Position; - byte[] buffer = new byte[stream.Length - position]; - if (buffer.Length > 0) { - stream.Position = position; - stream.ReadExactly(buffer); - stream.Write(buffer); - } - stream.Position = position; - stream.Write(data); - } + byte[] buffer = new byte[stream.Length - position]; + if (buffer.Length > 0) { + stream.Position = position; + stream.ReadExactly(buffer); + stream.Write(buffer); + } + stream.Position = position; + stream.Write(data); + } - public static void Remove(this Stream stream, long position, int amount) - { - byte[] buffer = new byte[stream.Length - (position + amount)]; - if (buffer.Length > 0) { - stream.Position = position + amount; - stream.ReadExactly(buffer); - stream.Position = position; - stream.Write(buffer); - } - stream.Position = position; - stream.SetLength(stream.Length - amount); - } + public static void Remove(this Stream stream, long position, int amount) + { + byte[] buffer = new byte[stream.Length - (position + amount)]; + if (buffer.Length > 0) { + stream.Position = position + amount; + stream.ReadExactly(buffer); + stream.Position = position; + stream.Write(buffer); + } + stream.Position = position; + stream.SetLength(stream.Length - amount); + } - public static byte[] GetDynamicBytes(this long value) - { - byte[] data = value.GetBytes(); - return data.Subset(0, GetPrimitiveLength(value)); - } + public static byte[] GetDynamicBytes(this long value) + { + byte[] data = value.GetBytes(); + return data.Subset(0, GetPrimitiveLength(value)); + } - public static int GetPrimitiveLength(this long value) - { - int length = 8; - for (int i = 1; i < 8; i++) { - if (value <= (1L << (i * 8))) { - length = i; - break; - } - } - return length; - } + public static int GetPrimitiveLength(this long value) + { + int length = 8; + for (int i = 1; i < 8; i++) { + if (value <= (1L << (i * 8))) { + length = i; + break; + } + } + return length; + } - public static byte[] GetBytes(this short value) => BitConverter.GetBytes(value); - public static byte[] GetBytes(this ushort value) => BitConverter.GetBytes(value); - public static byte[] GetBytes(this int value) => BitConverter.GetBytes(value); - public static byte[] GetBytes(this uint value) => BitConverter.GetBytes(value); - public static byte[] GetBytes(this long value) => BitConverter.GetBytes(value); - public static byte[] GetBytes(this ulong value) => BitConverter.GetBytes(value); - public static byte[] GetBytes(this double value) => BitConverter.GetBytes(value); + public static byte[] GetBytes(this short value) => BitConverter.GetBytes(value); + public static byte[] GetBytes(this ushort value) => BitConverter.GetBytes(value); + public static byte[] GetBytes(this int value) => BitConverter.GetBytes(value); + public static byte[] GetBytes(this uint value) => BitConverter.GetBytes(value); + public static byte[] GetBytes(this long value) => BitConverter.GetBytes(value); + public static byte[] GetBytes(this ulong value) => BitConverter.GetBytes(value); + public static byte[] GetBytes(this double value) => BitConverter.GetBytes(value); - public static short ToInt16(this byte[] bytes) => BitConverter.ToInt16(bytes); - public static ushort ToUInt16(this byte[] bytes) => BitConverter.ToUInt16(bytes); - public static int ToInt32(this byte[] bytes) => BitConverter.ToInt32(bytes); - public static uint ToUInt32(this byte[] bytes) => BitConverter.ToUInt32(bytes); - public static long ToInt64(this byte[] bytes) => BitConverter.ToInt64(bytes); - public static ulong ToUInt64(this byte[] bytes) => BitConverter.ToUInt64(bytes); - public static double ToDouble(this byte[] bytes) => BitConverter.ToDouble(bytes); + public static short ToInt16(this byte[] bytes) => BitConverter.ToInt16(bytes); + public static ushort ToUInt16(this byte[] bytes) => BitConverter.ToUInt16(bytes); + public static int ToInt32(this byte[] bytes) => BitConverter.ToInt32(bytes); + public static uint ToUInt32(this byte[] bytes) => BitConverter.ToUInt32(bytes); + public static long ToInt64(this byte[] bytes) => BitConverter.ToInt64(bytes); + public static ulong ToUInt64(this byte[] bytes) => BitConverter.ToUInt64(bytes); + public static double ToDouble(this byte[] bytes) => BitConverter.ToDouble(bytes); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Injector.cs b/Qrakhen.Qamp.Core/Injector.cs index 7599da4..224bf82 100644 --- a/Qrakhen.Qamp.Core/Injector.cs +++ b/Qrakhen.Qamp.Core/Injector.cs @@ -10,10 +10,10 @@ public class Injector public enum Scope { - /// Within the global scope of the file that is importing this library - Global, - /// Within the scope of the module this library exports - Module, - /// An extension of the built-in type - Extension + /// Within the global scope of the file that is importing this library + Global, + /// Within the scope of the module this library exports + Module, + /// An extension of the built-in type + Extension } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Logging/ILogger.cs b/Qrakhen.Qamp.Core/Logging/ILogger.cs index ef68216..0ef7295 100644 --- a/Qrakhen.Qamp.Core/Logging/ILogger.cs +++ b/Qrakhen.Qamp.Core/Logging/ILogger.cs @@ -5,79 +5,79 @@ namespace Qrakhen.Qamp.Core.Logging; public interface ILogger { - LogLevel Level { get; set; } + LogLevel Level { get; set; } - void Log(LogLevel level, params object?[] values); + void Log(LogLevel level, params object?[] values); - void Critical(params object?[] values); - void Error(params object?[] values); - void Warn(params object?[] values); - void Info(params object?[] values); - void Debug(params object?[] values); - void Trace(params object?[] values); - void Verbose(params object?[] values); - void Method(object? value = null, string? caller = null); + void Critical(params object?[] values); + void Error(params object?[] values); + void Warn(params object?[] values); + void Info(params object?[] values); + void Debug(params object?[] values); + void Trace(params object?[] values); + void Verbose(params object?[] values); + void Method(object? value = null, string? caller = null); } [Flags] public enum LogLevel { - Mute = 0x00, - Critical = 0x01, - Error = 0x02, - Warn = 0x04, - Info = 0x08, - Debug = 0x10, - Trace = 0x20, - Verbose = 0x40, - All = Critical | Error | Warn | Info | Debug | Trace | Verbose + Mute = 0x00, + Critical = 0x01, + Error = 0x02, + Warn = 0x04, + Info = 0x08, + Debug = 0x10, + Trace = 0x20, + Verbose = 0x40, + All = Critical | Error | Warn | Info | Debug | Trace | Verbose } public interface ILogFormatter { - string[] Format(object? value, int maxWidth = 80); + string[] Format(object? value, int maxWidth = 80); } public interface ILoggerService { - ILogger Get(string? name = null, LogLevel? level = null); - ILogger Get(string name, LogLevel? level = null); + ILogger Get(string? name = null, LogLevel? level = null); + ILogger Get(string name, LogLevel? level = null); } public class LoggerService { - private static readonly Dictionary _loggers = new Dictionary(); + private static readonly Dictionary _loggers = new Dictionary(); - public static LogLevel Default = LogLevel.All; + public static LogLevel Default = LogLevel.All; - public static ILogger Get(string? name = null, LogLevel? level = null) - { - level ??= Default; - string _name = nameof(T); - if (!string.IsNullOrEmpty(name)) - _name = $"{_name}:{name}"; - return Get(_name, level); - } + public static ILogger Get(string? name = null, LogLevel? level = null) + { + level ??= Default; + string _name = nameof(T); + if (!string.IsNullOrEmpty(name)) + _name = $"{_name}:{name}"; + return Get(_name, level); + } - public static ILogger Get(string name, LogLevel? level = null) - { - level ??= Default; - ILogger? logger; - if (_loggers.TryGetValue(name, out logger)) - return logger; - logger = new Logger(name, level.Value); - _loggers.Add(name, logger); - return logger; - } + public static ILogger Get(string name, LogLevel? level = null) + { + level ??= Default; + ILogger? logger; + if (_loggers.TryGetValue(name, out logger)) + return logger; + logger = new Logger(name, level.Value); + _loggers.Add(name, logger); + return logger; + } } public class Logger : ILogger, ILogFormatter { - public string Name { get; private set; } - private LogLevel _level; - public LogLevel Level { get => true ? LoggerService.Default : _level; set => _level = value; } + public string Name { get; private set; } + private LogLevel _level; + public LogLevel Level { get => true ? LoggerService.Default : _level; set => _level = value; } - private static Dictionary headers = new() { + private static Dictionary headers = new() { { LogLevel.Critical, (" !? ", " !? ") }, { LogLevel.Error, (" !! ", " ! ") }, { LogLevel.Warn, (" !> ", " ! ") }, @@ -87,7 +87,7 @@ public class Logger : ILogger, ILogFormatter { LogLevel.Verbose, (" > ", " ") }, }; - private static Dictionary colors = new() + private static Dictionary colors = new() { { LogLevel.Critical, ConsoleColor.DarkRed }, { LogLevel.Error, ConsoleColor.Red }, @@ -98,66 +98,63 @@ public class Logger : ILogger, ILogFormatter { LogLevel.Verbose, ConsoleColor.DarkGray }, }; - public Logger(string name, LogLevel level) - { - Name = name; - Level = level; - } + public Logger(string name, LogLevel level) + { + Name = name; + Level = level; + } - public string[] Format(object? value, int maxWidth = 80) - { - List result = []; - if (value == null) - result.Add("null"); - else if (value is string str) - result.AddRange(str.Split('\n')); - else if (value is Exception e) - { - result.Add(e.Message); - if (!string.IsNullOrEmpty(e.StackTrace)) - result.AddRange(e.StackTrace.Split('\n')); - } else - result.Add(value?.ToString() ?? "null"); + public string[] Format(object? value, int maxWidth = 80) + { + List result = []; + if (value == null) + result.Add("null"); + else if (value is string str) + result.AddRange(str.Split('\n')); + else if (value is Exception e) { + result.Add(e.Message); + if (!string.IsNullOrEmpty(e.StackTrace)) + result.AddRange(e.StackTrace.Split('\n')); + } else + result.Add(value?.ToString() ?? "null"); - return result.ToArray(); - } + return result.ToArray(); + } - public void Log(LogLevel level, params object?[] values) - { - if ((level & Level) != level) - return; + public void Log(LogLevel level, params object?[] values) + { + if ((level & Level) != level) + return; - var header = headers[level]; - Console.ForegroundColor = colors[level]; - foreach (var value in values) - { - var lines = Format(value); - for (int i = 0; i < lines.Length; i++) - Console.WriteLine($"{(i == 0 ? header.First : header.Extra)}{lines[i]}"); - } - Console.ForegroundColor = ConsoleColor.White; - } + var header = headers[level]; + Console.ForegroundColor = colors[level]; + foreach (var value in values) { + var lines = Format(value); + for (int i = 0; i < lines.Length; i++) + Console.WriteLine($"{(i == 0 ? header.First : header.Extra)}{lines[i]}"); + } + Console.ForegroundColor = ConsoleColor.White; + } - public void Critical(params object?[] values) => Log(LogLevel.Critical, values); - public void Error(params object?[] values) => Log(LogLevel.Error, values); - public void Warn(params object?[] values) => Log(LogLevel.Warn, values); - public void Info(params object?[] values) => Log(LogLevel.Info, values); - public void Debug(params object?[] values) => Log(LogLevel.Debug, values); - public void Trace(params object?[] values) => Log(LogLevel.Trace, values); - public void Verbose(params object?[] values) => Log(LogLevel.Verbose, values); + public void Critical(params object?[] values) => Log(LogLevel.Critical, values); + public void Error(params object?[] values) => Log(LogLevel.Error, values); + public void Warn(params object?[] values) => Log(LogLevel.Warn, values); + public void Info(params object?[] values) => Log(LogLevel.Info, values); + public void Debug(params object?[] values) => Log(LogLevel.Debug, values); + public void Trace(params object?[] values) => Log(LogLevel.Trace, values); + public void Verbose(params object?[] values) => Log(LogLevel.Verbose, values); - public void Method(object? value = null, [CallerMemberName] string? caller = null) - { - if (Level < LogLevel.Trace) - return; // save some ticks here + public void Method(object? value = null, [CallerMemberName] string? caller = null) + { + if (Level < LogLevel.Trace) + return; // save some ticks here - if (caller == null) - { - var st = new StackTrace(); - var previous = st.GetFrame(1)?.GetMethod(); - if (previous != null) - caller = $"{previous.DeclaringType?.Name}.{previous.Name}"; - } - Log(LogLevel.Trace, [ $"[{caller}] {value}" ]); - } + if (caller == null) { + var st = new StackTrace(); + var previous = st.GetFrame(1)?.GetMethod(); + if (previous != null) + caller = $"{previous.DeclaringType?.Name}.{previous.Name}"; + } + Log(LogLevel.Trace, [$"[{caller}] {value}"]); + } } diff --git a/Qrakhen.Qamp.Core/Tokenization/Dialect.cs b/Qrakhen.Qamp.Core/Tokenization/Dialect.cs index a60221d..8761a31 100644 --- a/Qrakhen.Qamp.Core/Tokenization/Dialect.cs +++ b/Qrakhen.Qamp.Core/Tokenization/Dialect.cs @@ -5,106 +5,106 @@ using static TokenType; public class Dialect { - // suuuper slow but meh, who cares - private Register _register = new(); + // suuuper slow but meh, who cares + private Register _register = new(); - public void Define(TokenType type, string sequence) - => _register[sequence] = type; + public void Define(TokenType type, string sequence) + => _register[sequence] = type; - public TokenType Get(string sequence) - => _register[sequence]; + public TokenType Get(string sequence) + => _register[sequence]; } public class DefaultDialect : Dialect { - public DefaultDialect() - { - Define(Null, "null"); - Define(GroupOpen, "("); - Define(GroupClose, ")"); - Define(ContextOpen, "{"); - Define(ContextClose, "}"); - Define(ArrayOpen, "["); - Define(ArrayClose, "]"); - Define(AddItem, "<+"); - Define(RemoveItem, "->"); - Define(Comma, ","); - Define(Dot, "."); - Define(Colon, ":"); - Define(Semicolon, ";"); - Define(Minus, "-"); - Define(Plus, "+"); - Define(MinusEqual, "-="); - Define(PlusEqual, "+="); - Define(Decrement, "++"); - Define(Increment, "--"); - Define(Slash, "/"); - Define(SlashEqual, "/="); - Define(Star, "*"); - Define(StarEqual, "*="); - Define(Modulo, "%"); - Define(ModuloEqual, "%="); - Define(BitwiseAnd, "&"); - Define(BitwiseOr, "|"); - Define(BitwiseXor, "^"); - Define(BitwiseNot, "~"); - Define(BitwiseLeft, "<<"); - Define(BitwiseRight, ">>"); - Define(Bang, "!"); - Define(BangEqual, "!="); - Define(Equal, "="); - Define(EqualEqual, "=="); - Define(Greater, ">"); - Define(GreaterEqual, ">="); - Define(Less, "<"); - Define(LessEqual, "<="); - Define(Question, "?"); - Define(DoubleQuestion, "??"); - Define(Identifier, "([_a-zA-Z][_a-zA-Z0-9]+?)"); - Define(String, "(:?('.+')|\".+\")"); - Define(Integer, "(\\d+)"); - Define(Decimal, ""); - Define(Hexadecimal, "0x([a-fA-F0-9]+)"); - Define(And, "&&"); - Define(Else, "else"); - Define(False, "false"); - Define(For, "for"); - Define(If, "if"); - Define(Or, "||"); - Define(This, "this"); - Define(True, "true"); - Define(Var, "var"); - Define(While, "while"); - Define(Do, "do"); - Define(Return, "return"); - Define(Ref, "ref"); - Define(Function, "function"); - Define(Class, "class"); - Define(Base, "base"); - Define(TypeOf, "typeof"); - Define(Print, "print"); - Define(Import, "import"); - Define(Export, "export"); - } + public DefaultDialect() + { + Define(Null, "null"); + Define(GroupOpen, "("); + Define(GroupClose, ")"); + Define(ContextOpen, "{"); + Define(ContextClose, "}"); + Define(ArrayOpen, "["); + Define(ArrayClose, "]"); + Define(AddItem, "<+"); + Define(RemoveItem, "->"); + Define(Comma, ","); + Define(Dot, "."); + Define(Colon, ":"); + Define(Semicolon, ";"); + Define(Minus, "-"); + Define(Plus, "+"); + Define(MinusEqual, "-="); + Define(PlusEqual, "+="); + Define(Decrement, "++"); + Define(Increment, "--"); + Define(Slash, "/"); + Define(SlashEqual, "/="); + Define(Star, "*"); + Define(StarEqual, "*="); + Define(Modulo, "%"); + Define(ModuloEqual, "%="); + Define(BitwiseAnd, "&"); + Define(BitwiseOr, "|"); + Define(BitwiseXor, "^"); + Define(BitwiseNot, "~"); + Define(BitwiseLeft, "<<"); + Define(BitwiseRight, ">>"); + Define(Bang, "!"); + Define(BangEqual, "!="); + Define(Equal, "="); + Define(EqualEqual, "=="); + Define(Greater, ">"); + Define(GreaterEqual, ">="); + Define(Less, "<"); + Define(LessEqual, "<="); + Define(Question, "?"); + Define(DoubleQuestion, "??"); + Define(Identifier, "([_a-zA-Z][_a-zA-Z0-9]+?)"); + Define(String, "(:?('.+')|\".+\")"); + Define(Integer, "(\\d+)"); + Define(Decimal, ""); + Define(Hexadecimal, "0x([a-fA-F0-9]+)"); + Define(And, "&&"); + Define(Else, "else"); + Define(False, "false"); + Define(For, "for"); + Define(If, "if"); + Define(Or, "||"); + Define(This, "this"); + Define(True, "true"); + Define(Var, "var"); + Define(While, "while"); + Define(Do, "do"); + Define(Return, "return"); + Define(Ref, "ref"); + Define(Function, "function"); + Define(Class, "class"); + Define(Base, "base"); + Define(TypeOf, "typeof"); + Define(Print, "print"); + Define(Import, "import"); + Define(Export, "export"); + } } public class ClassicDialect : DefaultDialect { - public ClassicDialect() - { - Define(Null, "_"); - Define(AddItem, "<+"); - Define(RemoveItem, "->"); - Define(Equal, "<~"); - Define(This, ".~"); - Define(Var, "*~"); - Define(Return, "<:"); - Define(Ref, "*&"); - Define(Function, "fq"); - Define(Base, "^~"); - Define(TypeOf, "?:"); - Define(Print, "::"); - Define(Import, ""); - } + public ClassicDialect() + { + Define(Null, "_"); + Define(AddItem, "<+"); + Define(RemoveItem, "->"); + Define(Equal, "<~"); + Define(This, ".~"); + Define(Var, "*~"); + Define(Return, "<:"); + Define(Ref, "*&"); + Define(Function, "fq"); + Define(Base, "^~"); + Define(TypeOf, "?:"); + Define(Print, "::"); + Define(Import, ""); + } } diff --git a/Qrakhen.Qamp.Core/Tokenization/Reader.cs b/Qrakhen.Qamp.Core/Tokenization/Reader.cs index 883a437..f72edc4 100644 --- a/Qrakhen.Qamp.Core/Tokenization/Reader.cs +++ b/Qrakhen.Qamp.Core/Tokenization/Reader.cs @@ -8,371 +8,371 @@ namespace Qrakhen.Qamp.Core.Tokenization; internal static partial class ReaderPatterns { - [GeneratedRegex(@"((?:\d+)?\.(?:\d+))")] - public static partial Regex IsDecimal(); + [GeneratedRegex(@"((?:\d+)?\.(?:\d+))")] + public static partial Regex IsDecimal(); - [GeneratedRegex(@"(\d+)")] - public static partial Regex IsInteger(); + [GeneratedRegex(@"(\d+)")] + public static partial Regex IsInteger(); - [GeneratedRegex(@"0x([a-fA-F0-9]+)")] - public static partial Regex IsHexadecimal(); + [GeneratedRegex(@"0x([a-fA-F0-9]+)")] + public static partial Regex IsHexadecimal(); - public static readonly Dictionary Keywords = new(); - public static readonly Dictionary Aliases = new(); + public static readonly Dictionary Keywords = new(); + public static readonly Dictionary Aliases = new(); - private static void Define(string key, TokenType type) - { - // not ideal, but momentarily better than setting up complex dialects - if (Keywords.ContainsValue(type)) - Aliases[key] = Keywords.First(v => v.Value == type).Key; - Keywords[key] = type; - } + private static void Define(string key, TokenType type) + { + // not ideal, but momentarily better than setting up complex dialects + if (Keywords.ContainsValue(type)) + Aliases[key] = Keywords.First(v => v.Value == type).Key; + Keywords[key] = type; + } - static ReaderPatterns() - { - Define("false", False); - Define("true", True); - Define("null", Null); - Define("void", Null); - Define("and", And); - Define("else", Else); - Define("for", For); - Define("if", If); - Define("or", Or); - Define("this", This); - Define(".~", This); - Define("var", Var); - Define("*~", Var); - Define("while", While); - Define("do", Do); - Define("ref", Ref); - Define("function", Function); - Define("funqtion", Function); - Define("fq", Function); - Define("funq", Function); - Define("return", Return); - Define("<:", Return); - Define("class", Class); - Define("base", Base); - Define("^~", Base); - Define("typeof", TypeOf); - Define("?:", TypeOf); - Define("print", Print); - Define("::", Print); - Define("globals", PrintGlobals); - Define("stack", PrintStack); - Define("expr", PrintExpr); - Define("import", Import); - Define("export", Export); - } + static ReaderPatterns() + { + Define("false", False); + Define("true", True); + Define("null", Null); + Define("void", Null); + Define("and", And); + Define("else", Else); + Define("for", For); + Define("if", If); + Define("or", Or); + Define("this", This); + Define(".~", This); + Define("var", Var); + Define("*~", Var); + Define("while", While); + Define("do", Do); + Define("ref", Ref); + Define("function", Function); + Define("funqtion", Function); + Define("fq", Function); + Define("funq", Function); + Define("return", Return); + Define("<:", Return); + Define("class", Class); + Define("base", Base); + Define("^~", Base); + Define("typeof", TypeOf); + Define("?:", TypeOf); + Define("print", Print); + Define("::", Print); + Define("globals", PrintGlobals); + Define("stack", PrintStack); + Define("expr", PrintExpr); + Define("import", Import); + Define("export", Export); + } } public class Reader : IReader, IDisposable { - private const char EofByte = (char)0xFF; - private const int ChunkSize = 0x20; + private const char EofByte = (char)0xFF; + private const int ChunkSize = 0x20; - private readonly Stream _stream; - private readonly Tokens _tokens; + private readonly Stream _stream; + private readonly Tokens _tokens; - private readonly List _buffer; + private readonly List _buffer; - private readonly ILogger _logger = LoggerService.Get(); + private readonly ILogger _logger = LoggerService.Get(); - private int _line = 0; - private int _column = 0; - private int _current = 0; - private long _startIndex = 0; - private TokenPosition _startPosition = default; + private int _line = 0; + private int _column = 0; + private int _current = 0; + private long _startIndex = 0; + private TokenPosition _startPosition = default; - public bool Done => _stream.Position >= _stream.Length && - _current >= _buffer.Count; + public bool Done => _stream.Position >= _stream.Length && + _current >= _buffer.Count; - public TokenPosition CurrentPosition => new TokenPosition(_line, _column); + public TokenPosition CurrentPosition => new TokenPosition(_line, _column); - public Reader(Stream stream) - { - _stream = stream; - _stream.Position = 0; - _tokens = new Tokens(); - _buffer = []; - } + public Reader(Stream stream) + { + _stream = stream; + _stream.Position = 0; + _tokens = new Tokens(); + _buffer = []; + } - public void Dispose() - { - _stream.Dispose(); - } + public void Dispose() + { + _stream.Dispose(); + } - public Token NextToken(bool includeCompilationIrrelevant = false) - { - if (Done) - return Token.Eof(); + public Token NextToken(bool includeCompilationIrrelevant = false) + { + if (Done) + return Token.Eof(); - Token token = ReadToken(); + Token token = ReadToken(); - while (!includeCompilationIrrelevant && token.IsCompilationIrrelevant && !Done) - token = ReadToken(); + while (!includeCompilationIrrelevant && token.IsCompilationIrrelevant && !Done) + token = ReadToken(); - if (!includeCompilationIrrelevant && token.IsCompilationIrrelevant && Done) - return Token.Eof(); + if (!includeCompilationIrrelevant && token.IsCompilationIrrelevant && Done) + return Token.Eof(); - return token; - } + return token; + } - private char Next() - { - if (!Done && _current >= _buffer.Count) - Continue(); - if (Done) - return EofByte; - _column++; - return _buffer[_current++]; - } + private char Next() + { + if (!Done && _current >= _buffer.Count) + Continue(); + if (Done) + return EofByte; + _column++; + return _buffer[_current++]; + } - private char Peek(int delta = 0) - { - if (_current + delta >= _buffer.Count) - Continue(); - if (_current + delta >= _buffer.Count) - return EofByte; - return _buffer[_current + delta]; - } + private char Peek(int delta = 0) + { + if (_current + delta >= _buffer.Count) + Continue(); + if (_current + delta >= _buffer.Count) + return EofByte; + return _buffer[_current + delta]; + } - private Token ReadToken() - { - _startIndex = _current; - _startPosition = CurrentPosition; - string buffer = string.Empty; - char c = Next(); - buffer += c; + private Token ReadToken() + { + _startIndex = _current; + _startPosition = CurrentPosition; + string buffer = string.Empty; + char c = Next(); + buffer += c; - if (c == '\n' || c == '\r') { - var position = CurrentPosition; - if (c == '\r') - buffer += Next(); - _line++; - _column = 0; - return MakeToken(NewLine, buffer); - } + if (c == '\n' || c == '\r') { + var position = CurrentPosition; + if (c == '\r') + buffer += Next(); + _line++; + _column = 0; + return MakeToken(NewLine, buffer); + } - if (c == '#') { - var position = CurrentPosition; - do { - c = Next(); - buffer += c; - } while (c != '\n' && c != EofByte); - return MakeToken(Comment, buffer); - } - - if (c == ' ') { - var position = CurrentPosition; - while (Match(' ')) - buffer += ' '; - return MakeToken(Whitespace, buffer); - } - - if (c is '\'' or '"') { - string str = ReadUntil(buffer, c); - if (str[^1] != c || str.Length < 2) - return MakeToken(Error, str); - return MakeToken(TokenType.String, str.Substring(1, str.Length - 2)); - } - - if (IsDigit(c) || (c == '.' && IsDigit(Peek()))) { - do { - c = Peek(0); - if (IsDigit(c) || IsHex(c) || c == 'x' || c == '.') - buffer += Next(); - else - break; - } while (c != EofByte); - if (ReaderPatterns.IsDecimal().TryMatch(buffer, out Match match)) - return MakeToken(TokenType.Decimal, match.Groups[1].Value); - if (ReaderPatterns.IsHexadecimal().TryMatch(buffer, out match)) - return MakeToken(Hexadecimal, match.Groups[1].Value); - if (ReaderPatterns.IsInteger().TryMatch(buffer, out match)) - return MakeToken(Integer, match.Groups[1].Value); - throw new ReaderException($"Unrecognizable number detected <{buffer}>", this); - } - - if (IsLetter(c)) { - do { - c = Peek(); - if (IsLetter(c)) - buffer += Next(); - else - break; - } while (c != EofByte); - return MakeIdentifier(buffer); - } - - return MakeOperator(buffer); - } - - private string ReadUntil(string buffer, char until) - { - char c; - do { + if (c == '#') { + var position = CurrentPosition; + do { c = Next(); - if (c == EofByte) - return buffer; - /*throw new ReaderException( - $"Unexpected end of feed while trying to read string <{buffer}>", - this);*/ buffer += c; - } while (c != until || Peek(-2) == '\\'); - return buffer; - } + } while (c != '\n' && c != EofByte); + return MakeToken(Comment, buffer); + } - private Token MakeIdentifier(string buffer) - { - if (ReaderPatterns.Keywords.TryGetValue(buffer, out TokenType type)) - return MakeToken(type, buffer); - return MakeToken(Identifier, buffer); - } + if (c == ' ') { + var position = CurrentPosition; + while (Match(' ')) + buffer += ' '; + return MakeToken(Whitespace, buffer); + } - private bool Check(char c) => Peek(0) == c; + if (c is '\'' or '"') { + string str = ReadUntil(buffer, c); + if (str[^1] != c || str.Length < 2) + return MakeToken(Error, str); + return MakeToken(TokenType.String, str.Substring(1, str.Length - 2)); + } - private bool Match(char c) - { - if (!Check(c)) + if (IsDigit(c) || (c == '.' && IsDigit(Peek()))) { + do { + c = Peek(0); + if (IsDigit(c) || IsHex(c) || c == 'x' || c == '.') + buffer += Next(); + else + break; + } while (c != EofByte); + if (ReaderPatterns.IsDecimal().TryMatch(buffer, out Match match)) + return MakeToken(TokenType.Decimal, match.Groups[1].Value); + if (ReaderPatterns.IsHexadecimal().TryMatch(buffer, out match)) + return MakeToken(Hexadecimal, match.Groups[1].Value); + if (ReaderPatterns.IsInteger().TryMatch(buffer, out match)) + return MakeToken(Integer, match.Groups[1].Value); + throw new ReaderException($"Unrecognizable number detected <{buffer}>", this); + } + + if (IsLetter(c)) { + do { + c = Peek(); + if (IsLetter(c)) + buffer += Next(); + else + break; + } while (c != EofByte); + return MakeIdentifier(buffer); + } + + return MakeOperator(buffer); + } + + private string ReadUntil(string buffer, char until) + { + char c; + do { + c = Next(); + if (c == EofByte) + return buffer; + /*throw new ReaderException( + $"Unexpected end of feed while trying to read string <{buffer}>", + this);*/ + buffer += c; + } while (c != until || Peek(-2) == '\\'); + return buffer; + } + + private Token MakeIdentifier(string buffer) + { + if (ReaderPatterns.Keywords.TryGetValue(buffer, out TokenType type)) + return MakeToken(type, buffer); + return MakeToken(Identifier, buffer); + } + + private bool Check(char c) => Peek(0) == c; + + private bool Match(char c) + { + if (!Check(c)) + return false; + + Next(); + return true; + } + + private bool MatchSequence(char[] sequence, string buffer, TokenType type, out Token token) + { + token = Token.Void; + string _buffer = buffer; + for (int i = 0; i < sequence.Length; i++) { + char c = buffer.Length > i ? buffer[i] : Peek(i - buffer.Length); + if (sequence[i] != c) return false; + _buffer += c; + } - Next(); - return true; - } + token = MakeToken(type, _buffer); + return true; + } - private bool MatchSequence(char[] sequence, string buffer, TokenType type, out Token token) - { - token = Token.Void; - string _buffer = buffer; - for (int i = 0; i < sequence.Length; i++) { - char c = buffer.Length > i ? buffer[i] : Peek(i - buffer.Length); - if (sequence[i] != c) - return false; - _buffer += c; - } + private bool IsLetter(char c) => c is >= 'a' and <= 'z' or >= 'A' and <= 'Z' or '_'; - token = MakeToken(type, _buffer); - return true; - } + private bool IsDigit(char c) => c is >= '0' and <= '9'; - private bool IsLetter(char c) => c is >= 'a' and <= 'z' or >= 'A' and <= 'Z' or '_'; + private bool IsHex(char c) => c is >= 'a' and <= 'f' or >= 'A' and <= 'F' || IsDigit(c); - private bool IsDigit(char c) => c is >= '0' and <= '9'; + private Token MakeOperator(string buffer) + { + return buffer[0] switch { + '[' => MakeToken(ArrayOpen, buffer), + ']' => MakeToken(ArrayClose, buffer), + '{' => MakeToken(ContextOpen, buffer), + '}' => MakeToken(ContextClose, buffer), + '(' => MakeToken(GroupOpen, buffer), + ')' => MakeToken(GroupClose, buffer), + '.' => Check('~') ? + MakeToken(This, buffer + Next()) : + MakeToken(Dot, buffer), + ',' => MakeToken(Comma, buffer), + ';' => MakeToken(Semicolon, buffer), + ':' => Check(':') ? + MakeToken(Print, buffer + Next()) : + Check('[') ? + MakeToken(ListOpen, buffer + Next()) : + MakeToken(Colon, buffer), + '&' => Check('&') ? + MakeToken(And, buffer + Next()) : + MakeToken(BitwiseAnd, buffer), + '^' => Check('~') ? + MakeToken(Base, buffer + Next()) : + MakeToken(BitwiseXor, buffer), + '%' => Check('=') ? + MakeToken(ModuloEqual, buffer + Next()) : + MakeToken(Modulo, buffer), + '|' => Check('|') ? + MakeToken(Or, buffer + Next()) : + MakeToken(BitwiseOr, buffer), + '!' => Check('=') ? + MakeToken(BangEqual, buffer + Next()) : + MakeToken(Bang, buffer), + '+' => Check('+') ? + MakeToken(Increment, buffer + Next()) : + Check('=') ? + MakeToken(PlusEqual, buffer + Next()) : + MakeToken(Plus, buffer), + '-' => Check('-') ? + MakeToken(Decrement, buffer + Next()) : + Check('=') ? + MakeToken(MinusEqual, buffer + Next()) : + MakeToken(Minus, buffer), + '/' => Check('=') ? + MakeToken(SlashEqual, buffer + Next()) : + MakeToken(Slash, buffer), + '*' => Check('=') ? + MakeToken(StarEqual, buffer + Next()) : + Check('~') ? + MakeToken(Var, buffer + Next()) : + MakeToken(Star, buffer), + '=' => Check('=') ? + MakeToken(EqualEqual, buffer + Next()) : + MakeToken(Equal, buffer), + '<' => Check('~') ? + MakeToken(Equal, buffer + Next()) : + Check(':') ? + MakeToken(Return, buffer + Next()) : + Check('+') ? + MakeToken(AddItem, buffer + Next()) : + Check('<') ? + MakeToken(BitwiseLeft, buffer + Next()) : + Check('=') ? + MakeToken(LessEqual, buffer + Next()) : + Check('>') ? + MakeToken(TernaryElse, buffer + Next()) : + MakeToken(Less, buffer), + '>' => Check('>') ? + MakeToken(BitwiseRight, buffer + Next()) : + Check('=') ? + MakeToken(GreaterEqual, buffer + Next()) : + MakeToken(Greater, buffer), + '~' => Check('(') ? + MakeToken(Lambda, buffer) : + MakeToken(BitwiseNot, buffer), + '?' => Check('?') ? + MakeToken(DoubleQuestion, buffer + Next()) : + Check(':') ? + MakeToken(TypeOf, buffer + Next()) : + MakeToken(Question, buffer), + _ => MakeToken(Error, buffer) //throw new ReaderException($"Could not identify operator <{buffer}>", this) + }; + } - private bool IsHex(char c) => c is >= 'a' and <= 'f' or >= 'A' and <= 'F' || IsDigit(c); - - private Token MakeOperator(string buffer) - { - return buffer[0] switch { - '[' => MakeToken(ArrayOpen, buffer), - ']' => MakeToken(ArrayClose, buffer), - '{' => MakeToken(ContextOpen, buffer), - '}' => MakeToken(ContextClose, buffer), - '(' => MakeToken(GroupOpen, buffer), - ')' => MakeToken(GroupClose, buffer), - '.' => Check('~') ? - MakeToken(This, buffer + Next()) : - MakeToken(Dot, buffer), - ',' => MakeToken(Comma, buffer), - ';' => MakeToken(Semicolon, buffer), - ':' => Check(':') ? - MakeToken(Print, buffer + Next()) : - Check('[') ? - MakeToken(ListOpen, buffer + Next()) : - MakeToken(Colon, buffer), - '&' => Check('&') ? - MakeToken(And, buffer + Next()) : - MakeToken(BitwiseAnd, buffer), - '^' => Check('~') ? - MakeToken(Base, buffer + Next()) : - MakeToken(BitwiseXor, buffer), - '%' => Check('=') ? - MakeToken(ModuloEqual, buffer + Next()) : - MakeToken(Modulo, buffer), - '|' => Check('|') ? - MakeToken(Or, buffer + Next()) : - MakeToken(BitwiseOr, buffer), - '!' => Check('=') ? - MakeToken(BangEqual, buffer + Next()) : - MakeToken(Bang, buffer), - '+' => Check('+') ? - MakeToken(Increment, buffer + Next()) : - Check('=') ? - MakeToken(PlusEqual, buffer + Next()) : - MakeToken(Plus, buffer), - '-' => Check('-') ? - MakeToken(Decrement, buffer + Next()) : - Check('=') ? - MakeToken(MinusEqual, buffer + Next()) : - MakeToken(Minus, buffer), - '/' => Check('=') ? - MakeToken(SlashEqual, buffer + Next()) : - MakeToken(Slash, buffer), - '*' => Check('=') ? - MakeToken(StarEqual, buffer + Next()) : - Check('~') ? - MakeToken(Var, buffer + Next()) : - MakeToken(Star, buffer), - '=' => Check('=') ? - MakeToken(EqualEqual, buffer + Next()) : - MakeToken(Equal, buffer), - '<' => Check('~') ? - MakeToken(Equal, buffer + Next()) : - Check(':') ? - MakeToken(Return, buffer + Next()) : - Check('+') ? - MakeToken(AddItem, buffer + Next()) : - Check('<') ? - MakeToken(BitwiseLeft, buffer + Next()) : - Check('=') ? - MakeToken(LessEqual, buffer + Next()) : - Check('>') ? - MakeToken(TernaryElse, buffer + Next()) : - MakeToken(Less, buffer), - '>' => Check('>') ? - MakeToken(BitwiseRight, buffer + Next()) : - Check('=') ? - MakeToken(GreaterEqual, buffer + Next()) : - MakeToken(Greater, buffer), - '~' => Check('(') ? - MakeToken(Lambda, buffer) : - MakeToken(BitwiseNot, buffer), - '?' => Check('?') ? - MakeToken(DoubleQuestion, buffer + Next()) : - Check(':') ? - MakeToken(TypeOf, buffer + Next()) : - MakeToken(Question, buffer), - _ => MakeToken(Error, buffer) //throw new ReaderException($"Could not identify operator <{buffer}>", this) - }; - } + private Token MakeToken(TokenType type, string buffer) + { + return new Token( + type, + buffer, + _startPosition, + new StreamSpan(_startIndex, _current - _startIndex)); + } - private Token MakeToken(TokenType type, string buffer) - { - return new Token( - type, - buffer, - _startPosition, - new StreamSpan(_startIndex, _current - _startIndex)); - } + private void Continue() + { + if (Done) + return; + long size = _stream.Length - _stream.Position; + if (size > ChunkSize) + size = ChunkSize; + byte[] buffer = new byte[size]; + int read = _stream.Read(buffer, 0, (int)size); + if (read < 0) + return; + _buffer.AddRange(Encoding.UTF8.GetChars(buffer)); + } - private void Continue() - { - if (Done) - return; - long size = _stream.Length - _stream.Position; - if (size > ChunkSize) - size = ChunkSize; - byte[] buffer = new byte[size]; - int read = _stream.Read(buffer, 0, (int)size); - if (read < 0) - return; - _buffer.AddRange(Encoding.UTF8.GetChars(buffer)); - } - - private readonly struct CaptureHandle(long start) - { - public readonly long Start = start; - } + private readonly struct CaptureHandle(long start) + { + public readonly long Start = start; + } } diff --git a/Qrakhen.Qamp.Core/Tokenization/Token.cs b/Qrakhen.Qamp.Core/Tokenization/Token.cs index 2bf8d9f..76baa2d 100644 --- a/Qrakhen.Qamp.Core/Tokenization/Token.cs +++ b/Qrakhen.Qamp.Core/Tokenization/Token.cs @@ -7,36 +7,36 @@ public readonly record struct Token( StreamSpan Span = default ) { - public static Token Void = new(TokenType.Void); - public static Token Error(string? message = null) => new Token(TokenType.Error, message); - public static Token Eof(string? message = null) => new Token(TokenType.Eof, message); + public static Token Void = new(TokenType.Void); + public static Token Error(string? message = null) => new Token(TokenType.Error, message); + public static Token Eof(string? message = null) => new Token(TokenType.Eof, message); - public override string ToString() - { - return $"[@{Position}] <{Type}> ({Value ?? "?"})"; - } + public override string ToString() + { + return $"[@{Position}] <{Type}> ({Value ?? "?"})"; + } - public bool IsCompilationIrrelevant => Type == TokenType.NewLine || Type == TokenType.Comment || Type == TokenType.Whitespace; + public bool IsCompilationIrrelevant => Type == TokenType.NewLine || Type == TokenType.Comment || Type == TokenType.Whitespace; } public readonly record struct StreamSpan(long Start = -1, long Length = 0); public readonly record struct TokenPosition(int Line = -1, int Column = -1) { - public static readonly TokenPosition None = new(-1, -1); + public static readonly TokenPosition None = new(-1, -1); - public bool IsNone => this == None; + public bool IsNone => this == None; - public override string ToString() - { - return $"{Line}:{Column}"; - } + public override string ToString() + { + return $"{Line}:{Column}"; + } - public TokenPosition Previous => new(Line, Column - 1); + public TokenPosition Previous => new(Line, Column - 1); - public static TokenPosition operator +(TokenPosition a, TokenPosition b) => - new(a.Line + b.Line, a.Column + b.Column); + public static TokenPosition operator +(TokenPosition a, TokenPosition b) => + new(a.Line + b.Line, a.Column + b.Column); - public static TokenPosition operator -(TokenPosition a, TokenPosition b) => - new(a.Line - b.Line, a.Column - b.Column); + public static TokenPosition operator -(TokenPosition a, TokenPosition b) => + new(a.Line - b.Line, a.Column - b.Column); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Tokenization/TokenType.cs b/Qrakhen.Qamp.Core/Tokenization/TokenType.cs index 49010ef..85ccccc 100644 --- a/Qrakhen.Qamp.Core/Tokenization/TokenType.cs +++ b/Qrakhen.Qamp.Core/Tokenization/TokenType.cs @@ -3,7 +3,7 @@ using static TokenType; [Flags] -public enum TokenType +public enum TokenType { Error = -1, Void = 0, @@ -108,29 +108,29 @@ public enum TokenType public static class TokenTypeExtensions // iknow, i know, gotta make this flagged rather than THIS { - public static bool IsBracket(this TokenType type) - => type is GroupClose or GroupOpen or ContextClose or ContextOpen or ArrayClose or ArrayOpen or ListOpen or Lambda; + public static bool IsBracket(this TokenType type) + => type is GroupClose or GroupOpen or ContextClose or ContextOpen or ArrayClose or ArrayOpen or ListOpen or Lambda; - public static bool IsString(this TokenType type) - => type is TokenType.String; + public static bool IsString(this TokenType type) + => type is TokenType.String; - public static bool IsNumber(this TokenType type) - => type is Integer or Decimal; + public static bool IsNumber(this TokenType type) + => type is Integer or Decimal; - public static bool IsIdentifier(this TokenType type) - => type is Identifier; + public static bool IsIdentifier(this TokenType type) + => type is Identifier; - public static bool IsControl(this TokenType type) - => type is If or Var or Class or Else or For or While or Do or Return or And or Or or TypeOf or Print; + public static bool IsControl(this TokenType type) + => type is If or Var or Class or Else or For or While or Do or Return or And or Or or TypeOf or Print; - public static bool IsBoolean(this TokenType type) - => type is True or False; + public static bool IsBoolean(this TokenType type) + => type is True or False; - public static bool IsOperator(this TokenType type) - => !type.IsBracket() && - !type.IsString() && - !type.IsNumber() && - !type.IsIdentifier() && - !type.IsControl() && - !type.IsBoolean(); + public static bool IsOperator(this TokenType type) + => !type.IsBracket() && + !type.IsString() && + !type.IsNumber() && + !type.IsIdentifier() && + !type.IsControl() && + !type.IsBoolean(); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Tokenization/Tokens.cs b/Qrakhen.Qamp.Core/Tokenization/Tokens.cs index 4f45f5b..7041ae6 100644 --- a/Qrakhen.Qamp.Core/Tokenization/Tokens.cs +++ b/Qrakhen.Qamp.Core/Tokenization/Tokens.cs @@ -4,19 +4,18 @@ namespace Qrakhen.Qamp.Core.Tokenization; public class Tokens : IDebug { - private readonly List _tokens = new(); + private readonly List _tokens = new(); - public Token[] GetTokens() => _tokens.ToArray(); + public Token[] GetTokens() => _tokens.ToArray(); - public void Feed(Token token) => _tokens.Add(token); + public void Feed(Token token) => _tokens.Add(token); - public string Debug(DebugLevel level = DebugLevel.None) - { + public string Debug(DebugLevel level = DebugLevel.None) + { string str = Debugger.GetContextString(this); - foreach (var token in _tokens) - { - str += $"\n {token}"; + foreach (var token in _tokens) { + str += $"\n {token}"; } return str; - } + } } diff --git a/Qrakhen.Qamp.Core/Values/Address.cs b/Qrakhen.Qamp.Core/Values/Address.cs index ce667ff..afb5ff0 100644 --- a/Qrakhen.Qamp.Core/Values/Address.cs +++ b/Qrakhen.Qamp.Core/Values/Address.cs @@ -5,8 +5,8 @@ namespace Qrakhen.Qamp.Core.Values; [StructLayout(LayoutKind.Sequential, Size = sizeof(long))] public readonly record struct Address(long Value) { - public override string ToString() => $"0x{Value:x8}"; + public override string ToString() => $"0x{Value:x8}"; - public static implicit operator long(Address address) => address.Value; - public static implicit operator Address(long value) => new(value); + public static implicit operator long(Address address) => address.Value; + public static implicit operator Address(long value) => new(value); } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Values/NativeExtension.cs b/Qrakhen.Qamp.Core/Values/NativeExtension.cs index d3b7132..0aafb2c 100644 --- a/Qrakhen.Qamp.Core/Values/NativeExtension.cs +++ b/Qrakhen.Qamp.Core/Values/NativeExtension.cs @@ -6,47 +6,47 @@ namespace Qrakhen.Qamp.Core.Values; public delegate Value ExtensionDelegate(Value target, Value[] parameters); public class NativeExtension( - ValueType targetType, - string name, + ValueType targetType, + string name, ExtensionDelegate callback, string[] parameters) { - private static readonly Register> _register = new(); + private static readonly Register> _register = new(); - public readonly string Name = name; - public readonly ValueType TargetType = targetType; - public readonly ExtensionDelegate Callback = callback; - public readonly string[] Parameters = parameters.ToArray(); + public readonly string Name = name; + public readonly ValueType TargetType = targetType; + public readonly ExtensionDelegate Callback = callback; + public readonly string[] Parameters = parameters.ToArray(); - public static NativeExtension? Get(ValueType targetType, string name) - { - if (!_register.Has(targetType)) - return null; - if (!_register[targetType].Has(name)) - return null; - return _register[targetType][name]; - } + public static NativeExtension? Get(ValueType targetType, string name) + { + if (!_register.Has(targetType)) + return null; + if (!_register[targetType].Has(name)) + return null; + return _register[targetType][name]; + } - public static void Register(ValueType targetType, - string name, - ExtensionDelegate callback, - params string[] parameters) - { - if (!_register.Has(targetType)) - _register.Add(targetType, new()); - if (_register[targetType].Has(name)) - throw new QampException($"Extension {name} already exists for type {targetType}."); - _register[targetType].Add(name, new NativeExtension(targetType, name, callback, parameters)); - } + public static void Register(ValueType targetType, + string name, + ExtensionDelegate callback, + params string[] parameters) + { + if (!_register.Has(targetType)) + _register.Add(targetType, new()); + if (_register[targetType].Has(name)) + throw new QampException($"Extension {name} already exists for type {targetType}."); + _register[targetType].Add(name, new NativeExtension(targetType, name, callback, parameters)); + } - static NativeExtension() - { - Register(ValueType.String, "Length", (v, p) => new Value((long)v.Ptr.As()!.Value!.Length), []); - Register(ValueType.String, "IndexOf", (v, p) => new Value((long)v.Ptr.As()!.Value!.IndexOf(p[0].Ptr.As()!.Value!)), [ "needle" ]); - } + static NativeExtension() + { + Register(ValueType.String, "Length", (v, p) => new Value((long)v.Ptr.As()!.Value!.Length), []); + Register(ValueType.String, "IndexOf", (v, p) => new Value((long)v.Ptr.As()!.Value!.IndexOf(p[0].Ptr.As()!.Value!)), ["needle"]); + } - public override string ToString() - { - return $"{TargetType}.{Name}({string.Join(", ", Parameters)}) (NativeExtension)"; - } + public override string ToString() + { + return $"{TargetType}.{Name}({string.Join(", ", Parameters)}) (NativeExtension)"; + } } diff --git a/Qrakhen.Qamp.Core/Values/Objects/Array.cs b/Qrakhen.Qamp.Core/Values/Objects/Array.cs index 1ddbac7..2f52efe 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Array.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Array.cs @@ -4,36 +4,36 @@ namespace Qrakhen.Qamp.Core.Values.Objects; public class Array(IEnumerable data) : ItemProvider(ValueType.Array) { - public Value[] Data = [..data]; - protected override void InnerSet(int index, Value value) - { - Data[index] = value; - } + public Value[] Data = [..data]; + protected override void InnerSet(int index, Value value) + { + Data[index] = value; + } - protected override Value InnerGet(int index) - { - return Data[index]; - } + protected override Value InnerGet(int index) + { + return Data[index]; + } - protected override void AssertValidAccesor(int index) - { - if (index < 0 || index > Data.Length) - throw new ItemProviderException($"Can not index '{index}' of array, as the index is outside its boundaries.", this); - } + protected override void AssertValidAccesor(int index) + { + if (index < 0 || index > Data.Length) + throw new ItemProviderException($"Can not index '{index}' of array, as the index is outside its boundaries.", this); + } - protected override int ExtractIndex(Value value) - { - int index; - if (value.IsSigned) - index = (int)value.Signed; - else if (value.IsUnsigned) - index = (int)value.Unsigned; - else - throw new ItemProviderException($"Can not use {value} as an accessor, as it is not an integer.", this); + protected override int ExtractIndex(Value value) + { + int index; + if (value.IsSigned) + index = (int)value.Signed; + else if (value.IsUnsigned) + index = (int)value.Unsigned; + else + throw new ItemProviderException($"Can not use {value} as an accessor, as it is not an integer.", this); - return index; - } + return index; + } - public override string ToString() => ToString(true); - public string ToString(bool detail) => detail ? $"[{string.Join(", ", Data)}]" : $"Array[{Data.Length}]"; + public override string ToString() => ToString(true); + public string ToString(bool detail) => detail ? $"[{string.Join(", ", Data)}]" : $"Array[{Data.Length}]"; } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Values/Objects/Class.cs b/Qrakhen.Qamp.Core/Values/Objects/Class.cs index 0276c74..c42cdb8 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Class.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Class.cs @@ -2,11 +2,11 @@ public class Class(string name) : Obj(ValueType.Class) { - public readonly string Name = name; - public Table Members = new(); + public readonly string Name = name; + public Table Members = new(); - public override string ToString() - { - return $"{Name} (Class)"; - } + public override string ToString() + { + return $"{Name} (Class)"; + } } diff --git a/Qrakhen.Qamp.Core/Values/Objects/Context.cs b/Qrakhen.Qamp.Core/Values/Objects/Context.cs index 5c39d62..b89879d 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Context.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Context.cs @@ -4,8 +4,8 @@ namespace Qrakhen.Qamp.Core.Values.Objects; public class Context(Function function, ValueType type = ValueType.Context) : Obj(type) { - public Function Function = function; - public PushStack Outers = new(); + public Function Function = function; + public PushStack Outers = new(); - public override string ToString() => $"{Function.Name}(){{}}"; + public override string ToString() => $"{Function.Name}(){{}}"; } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Values/Objects/Extension.cs b/Qrakhen.Qamp.Core/Values/Objects/Extension.cs index 69db23d..fd33171 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Extension.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Extension.cs @@ -2,10 +2,10 @@ public class Extension(ValueType targetType, Function function) : Context(function) { - public ValueType TargetType = targetType; + public ValueType TargetType = targetType; - public override string ToString() - { - return $"{TargetType}.{Function.Name}() (Extension)"; - } + public override string ToString() + { + return $"{TargetType}.{Function.Name}() (Extension)"; + } } diff --git a/Qrakhen.Qamp.Core/Values/Objects/Function.cs b/Qrakhen.Qamp.Core/Values/Objects/Function.cs index 6462f7d..c607ad1 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Function.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Function.cs @@ -5,16 +5,16 @@ namespace Qrakhen.Qamp.Core.Values.Objects; public class Function(string name, Segment segment, int outerCount, int argumentCount) : Obj(ValueType.Function) { - public readonly string Name = name; - public Segment Segment = segment; - public readonly int OuterCount = outerCount; - public readonly int ArgumentCount = argumentCount; + public readonly string Name = name; + public Segment Segment = segment; + public readonly int OuterCount = outerCount; + public readonly int ArgumentCount = argumentCount; - public override string ToString() => $"{Name}()"; + public override string ToString() => $"{Name}()"; - public byte[] Serialize(bool topLevel = false) - { - List result = + public byte[] Serialize(bool topLevel = false) + { + List result = [ .. string.IsNullOrEmpty(Name) ? [] : Encoding.ASCII.GetBytes(Name), 0, @@ -22,13 +22,13 @@ public class Function(string name, Segment segment, int outerCount, int argument .. OuterCount.GetBytes(), .. Segment.Serialize() ]; - if (topLevel) { - result.AddRange([0xFF, 0xF0]); - result.AddRange(String.SerializeStrings()); - result.AddRange([0x0F, 0xFF, 0xFF, 0xF1]); - result.AddRange(Ptr.SerializeFunctions()); - result.AddRange([0x0F, 0xFF]); - } - return result.ToArray(); - } + if (topLevel) { + result.AddRange([0xFF, 0xF0]); + result.AddRange(String.SerializeStrings()); + result.AddRange([0x0F, 0xFF, 0xFF, 0xF1]); + result.AddRange(Ptr.SerializeFunctions()); + result.AddRange([0x0F, 0xFF]); + } + return result.ToArray(); + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Values/Objects/Instance.cs b/Qrakhen.Qamp.Core/Values/Objects/Instance.cs index afa23ef..eae2781 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Instance.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Instance.cs @@ -2,18 +2,18 @@ public class Instance(Class @class) : Obj(ValueType.Instance) { - public readonly Class Class = @class; - public Table Values = new(); + public readonly Class Class = @class; + public Table Values = new(); - public override string ToString() - { - string str = $"{Class.Name} {{\n"; - foreach (var member in Class.Members) { - str += $" {member.Key}: {member.Value},\n"; - } - foreach (var value in Values) { - str += $" {value.Key}: {value.Value},\n"; - } - return $"{str}}}"; - } + public override string ToString() + { + string str = $"{Class.Name} {{\n"; + foreach (var member in Class.Members) { + str += $" {member.Key}: {member.Value},\n"; + } + foreach (var value in Values) { + str += $" {value.Key}: {value.Value},\n"; + } + return $"{str}}}"; + } } diff --git a/Qrakhen.Qamp.Core/Values/Objects/ItemProvider.cs b/Qrakhen.Qamp.Core/Values/Objects/ItemProvider.cs index 115c9df..4d41ab1 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/ItemProvider.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/ItemProvider.cs @@ -2,25 +2,25 @@ public abstract class ItemProvider(ValueType type) : Obj(type) { - public void Set(Value index, Value value) - { - T _index = ExtractIndex(index); - AssertValidAccesor(_index); - InnerSet(_index, value); - } + public void Set(Value index, Value value) + { + T _index = ExtractIndex(index); + AssertValidAccesor(_index); + InnerSet(_index, value); + } - public Value Get(Value index) - { - T _index = ExtractIndex(index); - AssertValidAccesor(_index); - return InnerGet(_index); - } + public Value Get(Value index) + { + T _index = ExtractIndex(index); + AssertValidAccesor(_index); + return InnerGet(_index); + } - protected abstract Value InnerGet(T index); - protected abstract void InnerSet(T index, Value value); + protected abstract Value InnerGet(T index); + protected abstract void InnerSet(T index, Value value); - protected abstract void AssertValidAccesor(T index); - protected abstract T ExtractIndex(Value value); + protected abstract void AssertValidAccesor(T index); + protected abstract T ExtractIndex(Value value); } public class ItemProviderException(string message, object context) : QampException(message, context); \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Values/Objects/List.cs b/Qrakhen.Qamp.Core/Values/Objects/List.cs index 4afe2a6..069a9e4 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/List.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/List.cs @@ -2,49 +2,49 @@ public class List(IEnumerable data) : ItemProvider(ValueType.List) { - public List Data = [..data]; - - public void Add(Value value) - { - Data.Add(value); - } + public List Data = [..data]; - public void Remove(Value index) - { - int _index = ExtractIndex(index); - AssertValidAccesor(_index); - Data.RemoveAt(_index); - } + public void Add(Value value) + { + Data.Add(value); + } - protected override void InnerSet(int index, Value value) - { - Data[index] = value; - } + public void Remove(Value index) + { + int _index = ExtractIndex(index); + AssertValidAccesor(_index); + Data.RemoveAt(_index); + } - protected override Value InnerGet(int index) - { - return Data[index]; - } + protected override void InnerSet(int index, Value value) + { + Data[index] = value; + } - protected override void AssertValidAccesor(int index) - { - if (index < 0 || index > Data.Count) - throw new ItemProviderException($"Can not index '{index}' of list, as the index is outside its boundaries.", this); - } + protected override Value InnerGet(int index) + { + return Data[index]; + } - protected override int ExtractIndex(Value value) - { - int index; - if (value.IsSigned) - index = (int)value.Signed; - else if (value.IsUnsigned) - index = (int)value.Unsigned; - else - throw new ItemProviderException($"Can not use {value} as an accessor, as it is not an integer.", this); + protected override void AssertValidAccesor(int index) + { + if (index < 0 || index > Data.Count) + throw new ItemProviderException($"Can not index '{index}' of list, as the index is outside its boundaries.", this); + } - return index; - } + protected override int ExtractIndex(Value value) + { + int index; + if (value.IsSigned) + index = (int)value.Signed; + else if (value.IsUnsigned) + index = (int)value.Unsigned; + else + throw new ItemProviderException($"Can not use {value} as an accessor, as it is not an integer.", this); - public override string ToString() => ToString(true); - public string ToString(bool detail) => detail ? $":[{string.Join(", ", Data)}]" : $"List[{Data.Count}]"; + return index; + } + + public override string ToString() => ToString(true); + public string ToString(bool detail) => detail ? $":[{string.Join(", ", Data)}]" : $"List[{Data.Count}]"; } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Values/Objects/Method.cs b/Qrakhen.Qamp.Core/Values/Objects/Method.cs index 553cd4a..66058eb 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Method.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Method.cs @@ -2,5 +2,5 @@ public class Method(Function function, Value receiver) : Context(function, ValueType.Method) { - public Value Receiver = receiver; + public Value Receiver = receiver; } diff --git a/Qrakhen.Qamp.Core/Values/Objects/Native.cs b/Qrakhen.Qamp.Core/Values/Objects/Native.cs index 2cdaf94..7bed23f 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Native.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Native.cs @@ -2,8 +2,8 @@ public class Native(string name) : Class(name) { - public override string ToString() - { - return $"{Name} (Native)"; - } + public override string ToString() + { + return $"{Name} (Native)"; + } } diff --git a/Qrakhen.Qamp.Core/Values/Objects/Obj.cs b/Qrakhen.Qamp.Core/Values/Objects/Obj.cs index baf7c17..47cefa3 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Obj.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Obj.cs @@ -2,17 +2,17 @@ public class Obj(ValueType type) : IValue { - public bool __gcMarked { get; private set; } - public int __gcCount { get; private set; } = 1; + public bool __gcMarked { get; private set; } + public int __gcCount { get; private set; } = 1; - public readonly ValueType Type = type; + public readonly ValueType Type = type; - public ValueType ValueType => Type; + public ValueType ValueType => Type; - public static Value Create(Obj obj) - { - return new Value(Ptr.Create(obj)); - } + public static Value Create(Obj obj) + { + return new Value(Ptr.Create(obj)); + } - public override string ToString() => "Obj"; + public override string ToString() => "Obj"; } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Values/Objects/Outer.cs b/Qrakhen.Qamp.Core/Values/Objects/Outer.cs index 0aa48b9..b4420e2 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Outer.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Outer.cs @@ -9,32 +9,31 @@ using T = ValueType; /// public class Outer(Pointer target) : Obj(T.Outer) { - private Value _stored = Value.Void; - public Pointer Target = target; + private Value _stored = Value.Void; + public Pointer Target = target; - public bool IsClosed { get; private set; } + public bool IsClosed { get; private set; } - /// - /// Dynamic getter & setter that returns or writes to either the target value directly, - /// or the stored value if this has been closed. - /// - public Value Value - { - get => IsClosed ? _stored : Target!.Get(); - set { - if (IsClosed) - _stored = value; - else - Target.Set(value); - } - } + /// + /// Dynamic getter & setter that returns or writes to either the target value directly, + /// or the stored value if this has been closed. + /// + public Value Value { + get => IsClosed ? _stored : Target!.Get(); + set { + if (IsClosed) + _stored = value; + else + Target.Set(value); + } + } - public Value Close() - { - if (IsClosed) - throw new Exception($"meh, something not right here (cant close already closed outer)"); - _stored = Target!.Get(); - IsClosed = true; - return _stored; - } + public Value Close() + { + if (IsClosed) + throw new Exception($"meh, something not right here (cant close already closed outer)"); + _stored = Target!.Get(); + IsClosed = true; + return _stored; + } } diff --git a/Qrakhen.Qamp.Core/Values/Objects/String.cs b/Qrakhen.Qamp.Core/Values/Objects/String.cs index 446f54a..a37015d 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/String.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/String.cs @@ -5,46 +5,46 @@ namespace Qrakhen.Qamp.Core.Values.Objects; public class String(string? value) : Obj(ValueType.String) { - private static readonly Register _strings = new(); + private static readonly Register _strings = new(); - public string? Value = value; + public string? Value = value; - public override string ToString() => Value ?? "null"; + public override string ToString() => Value ?? "null"; - public uint GetHash() - { - if (string.IsNullOrEmpty(value)) - return 0; + public uint GetHash() + { + if (string.IsNullOrEmpty(value)) + return 0; - return Value.GetHash(); - } + return Value.GetHash(); + } - public static Value Make(string? value) - { - String? str; - var hash = value?.GetHash() ?? 0; - if (!_strings.TryGet(hash, out str)) { - str = new String(value); - _strings.Add(hash, str); - } + public static Value Make(string? value) + { + String? str; + var hash = value?.GetHash() ?? 0; + if (!_strings.TryGet(hash, out str)) { + str = new String(value); + _strings.Add(hash, str); + } - return Create(str); - } + return Create(str); + } - public static byte[] SerializeStrings() - { - List result = new(); - foreach (var pair in _strings) { - String str = pair.Value; - if (str == null || str.__gcMarked) - continue; - byte[] bytes; - bytes = Encoding.ASCII.GetBytes(str.Value!); - result.AddRange(pair.Key.GetBytes()); - result.AddRange(bytes.Length.GetBytes()); - result.AddRange(bytes); - result.Add(0); - } - return result.ToArray(); - } + public static byte[] SerializeStrings() + { + List result = new(); + foreach (var pair in _strings) { + String str = pair.Value; + if (str == null || str.__gcMarked) + continue; + byte[] bytes; + bytes = Encoding.ASCII.GetBytes(str.Value!); + result.AddRange(pair.Key.GetBytes()); + result.AddRange(bytes.Length.GetBytes()); + result.AddRange(bytes); + result.Add(0); + } + return result.ToArray(); + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Values/Objects/Structure.cs b/Qrakhen.Qamp.Core/Values/Objects/Structure.cs index 08db111..ecaac94 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Structure.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Structure.cs @@ -2,36 +2,36 @@ public class Structure(IEnumerable> data) : ItemProvider(ValueType.Structure) { - public bool Sealed; - public Dictionary Data = new(data); + public bool Sealed; + public Dictionary Data = new(data); - protected override void InnerSet(string index, Value value) - { - Data[index] = value; - } + protected override void InnerSet(string index, Value value) + { + Data[index] = value; + } - protected override Value InnerGet(string index) - { - return Data[index]; - } + protected override Value InnerGet(string index) + { + return Data[index]; + } - protected override void AssertValidAccesor(string index) - { - if (Sealed && !Data.ContainsKey(index)) - throw new ItemProviderException($"Can not set non-existent key '{index}' of sealed structure.", this); - } + protected override void AssertValidAccesor(string index) + { + if (Sealed && !Data.ContainsKey(index)) + throw new ItemProviderException($"Can not set non-existent key '{index}' of sealed structure.", this); + } - protected override string ExtractIndex(Value value) - { - string index; - if (value.IsString) - index = value.Ptr.As()!.Value!; - else - throw new ItemProviderException($"Can not use {value} as an accessor, as it is not a string.", this); + protected override string ExtractIndex(Value value) + { + string index; + if (value.IsString) + index = value.Ptr.As()!.Value!; + else + throw new ItemProviderException($"Can not use {value} as an accessor, as it is not a string.", this); - return index; - } + return index; + } - public override string ToString() => ToString(true); - public string ToString(bool detail) => detail ? $"{{{string.Join("\n,", Data)}}}" : $"Structure{{{Data.Count}}}"; + public override string ToString() => ToString(true); + public string ToString(bool detail) => detail ? $"{{{string.Join("\n,", Data)}}}" : $"Structure{{{Data.Count}}}"; } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Values/Ptr.cs b/Qrakhen.Qamp.Core/Values/Ptr.cs index c682e53..18ee0b0 100644 --- a/Qrakhen.Qamp.Core/Values/Ptr.cs +++ b/Qrakhen.Qamp.Core/Values/Ptr.cs @@ -7,66 +7,66 @@ namespace Qrakhen.Qamp.Core.Values; [StructLayout(LayoutKind.Sequential, Size = sizeof(ulong))] public readonly struct Ptr { - private static readonly PushStack _register = new(); + private static readonly PushStack _register = new(); - [Serialized] public readonly Address Address; + [Serialized] public readonly Address Address; - //private readonly IntPtr _pointer; - //public IntPtr Pointer => _pointer; + //private readonly IntPtr _pointer; + //public IntPtr Pointer => _pointer; - public Obj? Value { - get { - if (_register.TryGet(Address, out Obj obj)) - return obj; - return null; - //if (_pointer == IntPtr.Zero) - // throw new ObjectDisposedException(nameof(Ptr)); - //return (Obj)GCHandle.FromIntPtr(_pointer).Target!; - } - } + public Obj? Value { + get { + if (_register.TryGet(Address, out Obj obj)) + return obj; + return null; + //if (_pointer == IntPtr.Zero) + // throw new ObjectDisposedException(nameof(Ptr)); + //return (Obj)GCHandle.FromIntPtr(_pointer).Target!; + } + } - private Ptr(Address address) - { - //_pointer = GCHandle.ToIntPtr(GCHandle.Alloc(obj, GCHandleType.Normal)); - Address = address; - } + private Ptr(Address address) + { + //_pointer = GCHandle.ToIntPtr(GCHandle.Alloc(obj, GCHandleType.Normal)); + Address = address; + } - public static Ptr Create(Obj obj) - { - return new Ptr(_register.Add(obj)); - } + public static Ptr Create(Obj obj) + { + return new Ptr(_register.Add(obj)); + } - public T? As(bool throwWhenNull = true) where T : Obj - { - T? value = Value as T; - if (value == null && throwWhenNull) - throw new RuntimeException($"Could not convert Object {Value} to target type {typeof(T)}.", Value); - return value; - } + public T? As(bool throwWhenNull = true) where T : Obj + { + T? value = Value as T; + if (value == null && throwWhenNull) + throw new RuntimeException($"Could not convert Object {Value} to target type {typeof(T)}.", Value); + return value; + } - public override string ToString() => $"0x{Value}"; + public override string ToString() => $"0x{Value}"; - public static byte[] SerializeFunctions() - { - List result = new(); - for (int i = 0; i < _register.Count; i++) { - Obj obj = _register.Get(i); - if (obj == null || obj.__gcMarked) - continue; - byte[] bytes; - if (obj is Function function) { - bytes = function.Serialize(); - } else if (obj is Context context) { - bytes = context.Function.Serialize(); - } else { - continue; - } + public static byte[] SerializeFunctions() + { + List result = new(); + for (int i = 0; i < _register.Count; i++) { + Obj obj = _register.Get(i); + if (obj == null || obj.__gcMarked) + continue; + byte[] bytes; + if (obj is Function function) { + bytes = function.Serialize(); + } else if (obj is Context context) { + bytes = context.Function.Serialize(); + } else { + continue; + } - result.AddRange(i.GetBytes()); - result.AddRange(bytes.Length.GetBytes()); - result.AddRange(bytes); - result.Add(0); - } - return result.ToArray(); - } + result.AddRange(i.GetBytes()); + result.AddRange(bytes.Length.GetBytes()); + result.AddRange(bytes); + result.Add(0); + } + return result.ToArray(); + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Values/Ref.cs b/Qrakhen.Qamp.Core/Values/Ref.cs index 85d05a5..ae43f34 100644 --- a/Qrakhen.Qamp.Core/Values/Ref.cs +++ b/Qrakhen.Qamp.Core/Values/Ref.cs @@ -5,7 +5,7 @@ namespace Qrakhen.Qamp.Core.Values; [StructLayout(LayoutKind.Sequential, Size = sizeof(ulong))] public readonly unsafe struct Ref(Value* value) { - [Serialized] public readonly Value* Value = value; + [Serialized] public readonly Value* Value = value; - public override string ToString() => $"0x{*Value}"; + public override string ToString() => $"0x{*Value}"; } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Values/Value.cs b/Qrakhen.Qamp.Core/Values/Value.cs index 05d4f09..d04ca2e 100644 --- a/Qrakhen.Qamp.Core/Values/Value.cs +++ b/Qrakhen.Qamp.Core/Values/Value.cs @@ -9,125 +9,125 @@ namespace Qrakhen.Qamp.Core.Values; public interface IValue { - ValueType ValueType { get; } + ValueType ValueType { get; } } [StructLayout(LayoutKind.Explicit, Size = 0x10)] public readonly struct Value : IValue, ISerialize, IDebug { - public static readonly Value Void = new Value(); - public static readonly Value True = new Value(true); - public static readonly Value False = new Value(false); + public static readonly Value Void = new Value(); + public static readonly Value True = new Value(true); + public static readonly Value False = new Value(false); - [FieldOffset(0x00)] [Serialized] public readonly ulong Unsigned; - [FieldOffset(0x00)] [Serialized] public readonly long Signed; - [FieldOffset(0x00)] [Serialized] public readonly bool Bool; - [FieldOffset(0x00)] [Serialized] public readonly char Char; - [FieldOffset(0x00)] [Serialized] public readonly double Decimal; - [FieldOffset(0x00)] [Serialized] public readonly Address Address; - [FieldOffset(0x00)] [Serialized] public readonly Ptr Ptr; - [FieldOffset(0x00)] [Serialized] public readonly Ref Ref; - - [FieldOffset(0x08)] [Serialized] public readonly T Type; - - [FieldOffset(0x0c)] [Serialized] public readonly uint Meta; // like lengths of arrays or lists - - private Value(T type) => Type = type; - - public Value() : this(T.Void) { } - public Value(ulong unsigned) : this(T.Unsigned) => Unsigned = unsigned; - public Value(long signed) : this(T.Signed) => Signed = signed; - public Value(char character) : this(T.Char) => Char = character; - public Value(bool boolean) : this(T.Bool) => Bool = boolean; - public Value(double @decimal) : this(T.Decimal) => Decimal = @decimal; - public Value(Address address) : this(T.Address) => Address = address; - public Value(Ptr ptr) : this(ptr.Value?.Type ?? T.Pointer) => Ptr = ptr; - public Value(Ref @ref) : this(T.Reference) => Ref = @ref; + [FieldOffset(0x00)] [Serialized] public readonly ulong Unsigned; + [FieldOffset(0x00)] [Serialized] public readonly long Signed; + [FieldOffset(0x00)] [Serialized] public readonly bool Bool; + [FieldOffset(0x00)] [Serialized] public readonly char Char; + [FieldOffset(0x00)] [Serialized] public readonly double Decimal; + [FieldOffset(0x00)] [Serialized] public readonly Address Address; + [FieldOffset(0x00)] [Serialized] public readonly Ptr Ptr; + [FieldOffset(0x00)] [Serialized] public readonly Ref Ref; - public dynamic? Dynamic => AsDynamic(); + [FieldOffset(0x08)] [Serialized] public readonly T Type; - public T ValueType => Type; + [FieldOffset(0x0c)] [Serialized] public readonly uint Meta; // like lengths of arrays or lists - public bool IsNumber => Type <= T.Decimal; - public bool IsSigned => Is(T.Signed); - public bool IsUnsigned => Is(T.Unsigned); - public bool IsDecimal => Is(T.Decimal); - public bool IsBool => Is(T.Bool); - public bool IsString => Is(T.String); - public bool IsRef => Is(T.Reference, false); - public bool IsObj => Is(T.Object, false); + private Value(T type) => Type = type; - public bool IsFalsy => IsBool ? Bool == false : Unsigned == 0; + public Value() : this(T.Void) { } + public Value(ulong unsigned) : this(T.Unsigned) => Unsigned = unsigned; + public Value(long signed) : this(T.Signed) => Signed = signed; + public Value(char character) : this(T.Char) => Char = character; + public Value(bool boolean) : this(T.Bool) => Bool = boolean; + public Value(double @decimal) : this(T.Decimal) => Decimal = @decimal; + public Value(Address address) : this(T.Address) => Address = address; + public Value(Ptr ptr) : this(ptr.Value?.Type ?? T.Pointer) => Ptr = ptr; + public Value(Ref @ref) : this(T.Reference) => Ref = @ref; - public bool Is(T type, bool exact = true) - { + public dynamic? Dynamic => AsDynamic(); + + public T ValueType => Type; + + public bool IsNumber => Type <= T.Decimal; + public bool IsSigned => Is(T.Signed); + public bool IsUnsigned => Is(T.Unsigned); + public bool IsDecimal => Is(T.Decimal); + public bool IsBool => Is(T.Bool); + public bool IsString => Is(T.String); + public bool IsRef => Is(T.Reference, false); + public bool IsObj => Is(T.Object, false); + + public bool IsFalsy => IsBool ? Bool == false : Unsigned == 0; + + public bool Is(T type, bool exact = true) + { return exact ? (Type & type) == type : (Type & type) > 0; - } - - private unsafe dynamic? AsDynamic(bool throwWhenNull = true) - { - if (IsString) - return Ptr.As()!.Value; + } - if (IsObj) - return Ptr.Value; + private unsafe dynamic? AsDynamic(bool throwWhenNull = true) + { + if (IsString) + return Ptr.As()!.Value; - return Type switch { - T.Void => throwWhenNull ? throw new NullReferenceException() : null, - T.Unsigned => Unsigned, - T.Signed => Signed, - T.Decimal => Decimal, - T.Bool => Bool, - T.Address => Address, - T.Reference => (Value)(*Ref.Value), - _ => throwWhenNull ? throw new NullReferenceException() : null, - }; - } + if (IsObj) + return Ptr.Value; - public static Value FromAny(object? any = null) - { - if (any == null) - return new Value(); + return Type switch { + T.Void => throwWhenNull ? throw new NullReferenceException() : null, + T.Unsigned => Unsigned, + T.Signed => Signed, + T.Decimal => Decimal, + T.Bool => Bool, + T.Address => Address, + T.Reference => (Value)(*Ref.Value), + _ => throwWhenNull ? throw new NullReferenceException() : null, + }; + } - Type type = any.GetType(); + public static Value FromAny(object? any = null) + { + if (any == null) + return new Value(); - return new Value(); - } + Type type = any.GetType(); - public void __gcMark() - { - if (IsObj && Ptr.Value != null) { } - } - - public override bool Equals([NotNullWhen(true)] object? obj) - { - return obj switch { - Value value when Type == value.Type => Unsigned == value.Unsigned, - Value value => Dynamic?.Equals(value.Dynamic), - _ => false - }; - } + return new Value(); + } - public override int GetHashCode() => Unsigned.GetHashCode(); + public void __gcMark() + { + if (IsObj && Ptr.Value != null) { } + } - public override string ToString() => ToString(false); + public override bool Equals([NotNullWhen(true)] object? obj) + { + return obj switch { + Value value when Type == value.Type => Unsigned == value.Unsigned, + Value value => Dynamic?.Equals(value.Dynamic), + _ => false + }; + } - public string ToString(bool includeType) - { - if (!includeType) - return $"{AsDynamic(false)}"; + public override int GetHashCode() => Unsigned.GetHashCode(); - string type = Type.ToString(); - if (Type.HasFlag(T.Pointer)) - type = Ptr.Value?.Type.ToString() ?? "NullPtr"; + public override string ToString() => ToString(false); - return $"<{type}, {AsDynamic(false) ?? "null"}>"; - } + public string ToString(bool includeType) + { + if (!includeType) + return $"{AsDynamic(false)}"; - public string Debug(DebugLevel level = DebugLevel.None) - { + string type = Type.ToString(); + if (Type.HasFlag(T.Pointer)) + type = Ptr.Value?.Type.ToString() ?? "NullPtr"; + + return $"<{type}, {AsDynamic(false) ?? "null"}>"; + } + + public string Debug(DebugLevel level = DebugLevel.None) + { if (level < DebugLevel.Strong) - return Debugger.GetContextString(this); + return Debugger.GetContextString(this); string str = $"{Debugger.GetContextString(this)}\n"; @@ -145,22 +145,22 @@ public readonly struct Value : IValue, ISerialize, IDebug ]; return str + string.Join("\n - ", lines); - } + } - public byte[] Serialize() - { - List result = [.. ((ushort)Type).GetBytes() ]; - byte[] bytes = Signed.GetBytes(); - result.Add((byte)bytes.Length); - result.AddRange(bytes); - result.Add(0x7F); - return result.ToArray(); - } + public byte[] Serialize() + { + List result = [.. ((ushort)Type).GetBytes() ]; + byte[] bytes = Signed.GetBytes(); + result.Add((byte)bytes.Length); + result.AddRange(bytes); + result.Add(0x7F); + return result.ToArray(); + } - public static Value Deserialize(byte[] data) - { - return Void; - } + public static Value Deserialize(byte[] data) + { + return Void; + } } public class SerializedAttribute : Attribute; \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Values/ValueExtensions.cs b/Qrakhen.Qamp.Core/Values/ValueExtensions.cs index f4e4c6e..ee246ae 100644 --- a/Qrakhen.Qamp.Core/Values/ValueExtensions.cs +++ b/Qrakhen.Qamp.Core/Values/ValueExtensions.cs @@ -4,5 +4,5 @@ namespace Qrakhen.Qamp.Core.Values; internal static class ValueExtensions { - + } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Values/ValueType.cs b/Qrakhen.Qamp.Core/Values/ValueType.cs index 71ab8d0..3e503d3 100644 --- a/Qrakhen.Qamp.Core/Values/ValueType.cs +++ b/Qrakhen.Qamp.Core/Values/ValueType.cs @@ -7,39 +7,39 @@ [Flags] public enum ValueType { - Undefined = -1, - Void = 0x0000, - Unsigned = 0x0001, - Signed = 0x0002, - Decimal = 0x0004, - Char = 0x0008, - Bool = 0x0010, + Undefined = -1, + Void = 0x0000, + Unsigned = 0x0001, + Signed = 0x0002, + Decimal = 0x0004, + Char = 0x0008, + Bool = 0x0010, - Number = Unsigned | Signed | Decimal, - Integer = Unsigned | Signed | Char, - Primitive = Integer | Decimal | Bool, + Number = Unsigned | Signed | Decimal, + Integer = Unsigned | Signed | Char, + Primitive = Integer | Decimal | Bool, - Address = 0x0020, // coded with : symbol + Address = 0x0020, // coded with : symbol - // classes etc. here? + // classes etc. here? - Reference = 0x1000, - Pointer = 0x2000, + Reference = 0x1000, + Pointer = 0x2000, - Object = Pointer | 0x4000, - Native = Object | 0x0001, - String = Object | 0x0002, - Function = Object | 0x0020, - Context = Object | 0x0040, - Instance = Object | 0x0080, - Class = Object | 0x0100, - Method = Class | Function, - Outer = Object | 0x0200, + Object = Pointer | 0x4000, + Native = Object | 0x0001, + String = Object | 0x0002, + Function = Object | 0x0020, + Context = Object | 0x0040, + Instance = Object | 0x0080, + Class = Object | 0x0100, + Method = Class | Function, + Outer = Object | 0x0200, - ItemProvider = Object | 0x8000, // accessible with [n] or :n (getters / setters) - Array = ItemProvider | 0x0001, - List = ItemProvider | 0x0002, - Structure = ItemProvider | 0x0004, + ItemProvider = Object | 0x8000, // accessible with [n] or :n (getters / setters) + Array = ItemProvider | 0x0001, + List = ItemProvider | 0x0002, + Structure = ItemProvider | 0x0004, - Module = 0xFFFF + Module = 0xFFFF } \ No newline at end of file diff --git a/Qrakhen.Qamp.Editor/App.xaml.cs b/Qrakhen.Qamp.Editor/App.xaml.cs index 9e7fb82..bf015ce 100644 --- a/Qrakhen.Qamp.Editor/App.xaml.cs +++ b/Qrakhen.Qamp.Editor/App.xaml.cs @@ -8,13 +8,13 @@ namespace Qrakhen.Qamp.Editor; /// public partial class App : Application { - protected override void OnStartup(StartupEventArgs e) - { - MainWindow window = new MainWindow() { - DataContext = new ViewModel.EditorFrameViewModel() - }; + protected override void OnStartup(StartupEventArgs e) + { + MainWindow window = new MainWindow() { + DataContext = new ViewModel.EditorFrameViewModel() + }; - window.Show(); - } + window.Show(); + } } diff --git a/Qrakhen.Qamp.Editor/Commands/MoveCaretOptions.cs b/Qrakhen.Qamp.Editor/Commands/MoveCaretOptions.cs index 1e41038..440da18 100644 --- a/Qrakhen.Qamp.Editor/Commands/MoveCaretOptions.cs +++ b/Qrakhen.Qamp.Editor/Commands/MoveCaretOptions.cs @@ -2,6 +2,6 @@ namespace Qrakhen.Qamp.Editor.Commands; -public readonly record struct MoveCaretOptions(BufferPosition Position, - bool Relative = true, +public readonly record struct MoveCaretOptions(BufferPosition Position, + bool Relative = true, bool Jump = false); diff --git a/Qrakhen.Qamp.Editor/Commands/RelayCommand.cs b/Qrakhen.Qamp.Editor/Commands/RelayCommand.cs index 9f75f97..e9ee248 100644 --- a/Qrakhen.Qamp.Editor/Commands/RelayCommand.cs +++ b/Qrakhen.Qamp.Editor/Commands/RelayCommand.cs @@ -4,27 +4,27 @@ namespace Qrakhen.Qamp.Editor.Commands; public class RelayCommand : ICommand { - private readonly Action _execute; - private readonly Func _canExecute; + private readonly Action _execute; + private readonly Func _canExecute; - public RelayCommand(Action execute) : this(execute, null) { } + public RelayCommand(Action execute) : this(execute, null) { } - public RelayCommand(Action execute, Func? canExecute) - { - _execute = execute ?? throw new ArgumentNullException(nameof(execute)); - _canExecute = canExecute ?? (p => true); - } + public RelayCommand(Action execute, Func? canExecute) + { + _execute = execute ?? throw new ArgumentNullException(nameof(execute)); + _canExecute = canExecute ?? (p => true); + } - public RelayCommand(Action execute) : this(p => execute()) { } + public RelayCommand(Action execute) : this(p => execute()) { } - public RelayCommand(Action execute, Func canExecute) : this(p => execute(), p => canExecute()) { } + public RelayCommand(Action execute, Func canExecute) : this(p => execute(), p => canExecute()) { } - public event EventHandler? CanExecuteChanged { - add => CommandManager.RequerySuggested += value; - remove => CommandManager.RequerySuggested -= value; - } + public event EventHandler? CanExecuteChanged { + add => CommandManager.RequerySuggested += value; + remove => CommandManager.RequerySuggested -= value; + } - public bool CanExecute(object? parameter) => _canExecute(parameter); + public bool CanExecute(object? parameter) => _canExecute(parameter); - public void Execute(object? parameter) => _execute(parameter); + public void Execute(object? parameter) => _execute(parameter); } diff --git a/Qrakhen.Qamp.Editor/Controls/Caret.cs b/Qrakhen.Qamp.Editor/Controls/Caret.cs index 18b49c1..1f04e6b 100644 --- a/Qrakhen.Qamp.Editor/Controls/Caret.cs +++ b/Qrakhen.Qamp.Editor/Controls/Caret.cs @@ -18,42 +18,42 @@ public class Caret : Adorner private DispatcherTimer _blinkTimer; private DispatcherTimer _moveTimer; - public Caret(UIElement adornedElement, Brush brush, double height = 18, double thickness = 1.72) : base(adornedElement) - { - IsHitTestVisible = false; + public Caret(UIElement adornedElement, Brush brush, double height = 18, double thickness = 1.72) : base(adornedElement) + { + IsHitTestVisible = false; _enabled = true; - _height = height; - _brush = brush; - _pen = new Pen(brush, 1.92); + _height = height; + _brush = brush; + _pen = new Pen(brush, 1.92); - _blinkTimer = new DispatcherTimer(); - _blinkTimer.Interval = TimeSpan.FromMilliseconds(324); - _blinkTimer.Tick += new EventHandler((s, e) => { - Toggle(_blink = !_blink); - }); - _blinkTimer.Start(); + _blinkTimer = new DispatcherTimer(); + _blinkTimer.Interval = TimeSpan.FromMilliseconds(324); + _blinkTimer.Tick += new EventHandler((s, e) => { + Toggle(_blink = !_blink); + }); + _blinkTimer.Start(); - _moveTimer = new DispatcherTimer(); - _moveTimer.Interval = TimeSpan.FromMilliseconds(12); - _moveTimer.Tick += new EventHandler((s, e) => { - var delta = _targetPosition - _cursorPosition; - if (delta.Length > 2.4) - _cursorPosition += delta * .84; - else { - _cursorPosition = _targetPosition; - _moveTimer.Stop(); - _blinkTimer.Start(); - } - InvalidateVisual(); - }); - } + _moveTimer = new DispatcherTimer(); + _moveTimer.Interval = TimeSpan.FromMilliseconds(12); + _moveTimer.Tick += new EventHandler((s, e) => { + var delta = _targetPosition - _cursorPosition; + if (delta.Length > 2.4) + _cursorPosition += delta * .84; + else { + _cursorPosition = _targetPosition; + _moveTimer.Stop(); + _blinkTimer.Start(); + } + InvalidateVisual(); + }); + } - public void Toggle(bool hide) - { - _pen.Brush = hide ? Brushes.Transparent : _brush; + public void Toggle(bool hide) + { + _pen.Brush = hide ? Brushes.Transparent : _brush; InvalidateVisual(); - } + } public void Disable() { @@ -74,13 +74,13 @@ public class Caret : Adorner _cursorPosition = _targetPosition = newPosition; _enabled = true; Toggle(_blink = false); - _blinkTimer.Start(); + _blinkTimer.Start(); } - protected override void OnRender(DrawingContext drawingContext) - { - Point startPoint = new(_cursorPosition.X, _cursorPosition.Y); - Point endPoint = new(_cursorPosition.X, _cursorPosition.Y + _height); - drawingContext.DrawLine(_pen, startPoint, endPoint); - } + protected override void OnRender(DrawingContext drawingContext) + { + Point startPoint = new(_cursorPosition.X, _cursorPosition.Y); + Point endPoint = new(_cursorPosition.X, _cursorPosition.Y + _height); + drawingContext.DrawLine(_pen, startPoint, endPoint); + } } diff --git a/Qrakhen.Qamp.Editor/Controls/EditorFrame.xaml.cs b/Qrakhen.Qamp.Editor/Controls/EditorFrame.xaml.cs index 1c942e1..b63c086 100644 --- a/Qrakhen.Qamp.Editor/Controls/EditorFrame.xaml.cs +++ b/Qrakhen.Qamp.Editor/Controls/EditorFrame.xaml.cs @@ -135,16 +135,15 @@ public partial class EditorFrame : UserControl Point offset = ScrollView.TranslatePoint(position, ScrollView); - if (offset.X < 0 || - offset.Y < 0 || - offset.X >= ScrollView.ActualWidth || + if (offset.X < 0 || + offset.Y < 0 || + offset.X >= ScrollView.ActualWidth || offset.Y >= ScrollView.ActualHeight) { if (autoScroll) AutoScroll(offset); else HideCaret(); - } - else + } else MoveCaret(position); if (!CurrentSelection.IsVoid) { diff --git a/Qrakhen.Qamp.Editor/InputService.cs b/Qrakhen.Qamp.Editor/InputService.cs index 465da83..9ef5a50 100644 --- a/Qrakhen.Qamp.Editor/InputService.cs +++ b/Qrakhen.Qamp.Editor/InputService.cs @@ -22,38 +22,38 @@ public interface IInputHandler public enum ActionId { - None, - Undo, - Redo, - Copy, - Paste, - Delete, - MoveUp, - MoveDown, - MoveRight, - MoveLeft, - Submit, - Close + None, + Undo, + Redo, + Copy, + Paste, + Delete, + MoveUp, + MoveDown, + MoveRight, + MoveLeft, + Submit, + Close } public delegate void KeyEventListener(); public class InputService : IInputHandler { - public static bool LeftCtrlHeld => Keyboard.IsKeyDown(Key.LeftCtrl); - public static bool LeftShiftHeld => Keyboard.IsKeyDown(Key.LeftShift); - public static bool LeftAltHeld => Keyboard.IsKeyDown(Key.LeftAlt); - public static bool RightCtrlHeld => Keyboard.IsKeyDown(Key.RightCtrl); - public static bool RightShiftHeld => Keyboard.IsKeyDown(Key.RightShift); - public static bool RightAltHeld => Keyboard.IsKeyDown(Key.RightAlt); - public static bool CtrlHeld => LeftCtrlHeld || RightCtrlHeld; - public static bool ShiftHeld => LeftShiftHeld || RightShiftHeld; - public static bool AltHeld => LeftAltHeld || RightAltHeld; + public static bool LeftCtrlHeld => Keyboard.IsKeyDown(Key.LeftCtrl); + public static bool LeftShiftHeld => Keyboard.IsKeyDown(Key.LeftShift); + public static bool LeftAltHeld => Keyboard.IsKeyDown(Key.LeftAlt); + public static bool RightCtrlHeld => Keyboard.IsKeyDown(Key.RightCtrl); + public static bool RightShiftHeld => Keyboard.IsKeyDown(Key.RightShift); + public static bool RightAltHeld => Keyboard.IsKeyDown(Key.RightAlt); + public static bool CtrlHeld => LeftCtrlHeld || RightCtrlHeld; + public static bool ShiftHeld => LeftShiftHeld || RightShiftHeld; + public static bool AltHeld => LeftAltHeld || RightAltHeld; - public static void AddKeyListener(Key key, params Key[] modifiers) - { + public static void AddKeyListener(Key key, params Key[] modifiers) + { - } + } } public static class KeyHelper @@ -74,51 +74,51 @@ public static class KeyHelper _chars[Key.Q] = ['q', 'Q', '@']; - Add(Key.None); - Add(Key.Cancel); - Add(Key.Back); - Add(Key.Tab, '\t'); - Add(Key.LineFeed); - Add(Key.Clear); - Add(Key.Enter, '\n'); - Add(Key.Return); - Add(Key.Pause); - Add(Key.Capital); - Add(Key.CapsLock); - Add(Key.HangulMode); - Add(Key.KanaMode); - Add(Key.JunjaMode); - Add(Key.FinalMode); - Add(Key.HanjaMode); - Add(Key.KanjiMode); - Add(Key.Escape); - Add(Key.ImeConvert); - Add(Key.ImeNonConvert); - Add(Key.ImeAccept); - Add(Key.ImeModeChange); - Add(Key.Space, ' '); - Add(Key.PageUp); - Add(Key.Prior); - Add(Key.Next); - Add(Key.PageDown); - Add(Key.End); - Add(Key.Home); - Add(Key.Left); - Add(Key.Up); - Add(Key.Right); - Add(Key.Down); - Add(Key.Select); - Add(Key.Print); - Add(Key.Execute); - Add(Key.PrintScreen); - Add(Key.Snapshot); - Add(Key.Insert); - Add(Key.Delete); - Add(Key.Help); - Add(Key.LWin); - Add(Key.RWin); - Add(Key.Apps); - Add(Key.Sleep); + Add(Key.None); + Add(Key.Cancel); + Add(Key.Back); + Add(Key.Tab, '\t'); + Add(Key.LineFeed); + Add(Key.Clear); + Add(Key.Enter, '\n'); + Add(Key.Return); + Add(Key.Pause); + Add(Key.Capital); + Add(Key.CapsLock); + Add(Key.HangulMode); + Add(Key.KanaMode); + Add(Key.JunjaMode); + Add(Key.FinalMode); + Add(Key.HanjaMode); + Add(Key.KanjiMode); + Add(Key.Escape); + Add(Key.ImeConvert); + Add(Key.ImeNonConvert); + Add(Key.ImeAccept); + Add(Key.ImeModeChange); + Add(Key.Space, ' '); + Add(Key.PageUp); + Add(Key.Prior); + Add(Key.Next); + Add(Key.PageDown); + Add(Key.End); + Add(Key.Home); + Add(Key.Left); + Add(Key.Up); + Add(Key.Right); + Add(Key.Down); + Add(Key.Select); + Add(Key.Print); + Add(Key.Execute); + Add(Key.PrintScreen); + Add(Key.Snapshot); + Add(Key.Insert); + Add(Key.Delete); + Add(Key.Help); + Add(Key.LWin); + Add(Key.RWin); + Add(Key.Apps); + Add(Key.Sleep); Add(Key.D0, '0', '=', '}'); Add(Key.D1, '1', '!'); Add(Key.D2, '2', '"', '²'); diff --git a/Qrakhen.Qamp.Editor/MainWindow.xaml.cs b/Qrakhen.Qamp.Editor/MainWindow.xaml.cs index 9296620..fa437b3 100644 --- a/Qrakhen.Qamp.Editor/MainWindow.xaml.cs +++ b/Qrakhen.Qamp.Editor/MainWindow.xaml.cs @@ -4,8 +4,8 @@ namespace Qrakhen.Qamp.Editor; public partial class MainWindow : Window { - public MainWindow() - { - InitializeComponent(); - } + public MainWindow() + { + InitializeComponent(); + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Editor/Primitives/BufferPosition.cs b/Qrakhen.Qamp.Editor/Primitives/BufferPosition.cs index d7f4686..403a57f 100644 --- a/Qrakhen.Qamp.Editor/Primitives/BufferPosition.cs +++ b/Qrakhen.Qamp.Editor/Primitives/BufferPosition.cs @@ -4,18 +4,18 @@ public readonly record struct BufferPosition(int Line = 0, int Column = 0) { public bool IsInitial => Line == 0 && Column == 0; - public static readonly BufferPosition Initial = new(0, 0); - public static readonly BufferPosition Left = new(0, -1); - public static readonly BufferPosition Right = new(0, 1); - public static readonly BufferPosition Up = new(-1, 0); - public static readonly BufferPosition Down = new(1, 0); + public static readonly BufferPosition Initial = new(0, 0); + public static readonly BufferPosition Left = new(0, -1); + public static readonly BufferPosition Right = new(0, 1); + public static readonly BufferPosition Up = new(-1, 0); + public static readonly BufferPosition Down = new(1, 0); - public static BufferPosition operator +(BufferPosition left, BufferPosition right) - => new(left.Line + right.Line, left.Column + right.Column); + public static BufferPosition operator +(BufferPosition left, BufferPosition right) + => new(left.Line + right.Line, left.Column + right.Column); - public static BufferPosition operator -(BufferPosition left, BufferPosition right) - => new(left.Line - right.Line, left.Column - right.Column); + public static BufferPosition operator -(BufferPosition left, BufferPosition right) + => new(left.Line - right.Line, left.Column - right.Column); - public static BufferPosition operator *(BufferPosition left, int factor) - => new(left.Line * factor, left.Column * factor); + public static BufferPosition operator *(BufferPosition left, int factor) + => new(left.Line * factor, left.Column * factor); } diff --git a/Qrakhen.Qamp.Editor/Primitives/BufferRegion.cs b/Qrakhen.Qamp.Editor/Primitives/BufferRegion.cs index c3aeb86..84cfbe5 100644 --- a/Qrakhen.Qamp.Editor/Primitives/BufferRegion.cs +++ b/Qrakhen.Qamp.Editor/Primitives/BufferRegion.cs @@ -6,6 +6,13 @@ public struct BufferRegion(BufferPosition from, BufferPosition to) public bool IsVoid => (From - To).IsInitial; - public BufferPosition From = from; - public BufferPosition To = to; + public readonly BufferPosition From = from; + public BufferPosition To = to; + + public static BufferRegion operator +(BufferRegion left, BufferPosition right) + => new(left.From, left.To + right); + + public static BufferRegion operator -(BufferRegion left, BufferPosition right) + => new(left.From, left.To - right); + } \ No newline at end of file diff --git a/Qrakhen.Qamp.Editor/TextHelper.cs b/Qrakhen.Qamp.Editor/TextHelper.cs index 7c7c8b2..9afa3e4 100644 --- a/Qrakhen.Qamp.Editor/TextHelper.cs +++ b/Qrakhen.Qamp.Editor/TextHelper.cs @@ -5,25 +5,25 @@ namespace Qrakhen.Qamp.Editor; public static class TextHelper // temp { - public static double Size { get; set; } = 14; - public static double LineHeight { get; set; } = 18; - public static Brush DefaultColor { get; set; } = Brushes.AntiqueWhite; - public static Typeface Typeface { get; set; } = new( - new FontFamily("Consolas"), - FontStyles.Normal, - FontWeights.Normal, - FontStretches.Normal); + public static double Size { get; set; } = 14; + public static double LineHeight { get; set; } = 18; + public static Brush DefaultColor { get; set; } = Brushes.AntiqueWhite; + public static Typeface Typeface { get; set; } = new( + new FontFamily("Consolas"), + FontStyles.Normal, + FontWeights.Normal, + FontStretches.Normal); - public static FormattedText GetText(string text, double size, Brush? brush = null, double dpiScale = 1f) - { - return new FormattedText( - text, - System.Globalization.CultureInfo.CurrentCulture, - FlowDirection.LeftToRight, - Typeface, - size, - brush ?? DefaultColor, - dpiScale - ); - } + public static FormattedText GetText(string text, double size, Brush? brush = null, double dpiScale = 1f) + { + return new FormattedText( + text, + System.Globalization.CultureInfo.CurrentCulture, + FlowDirection.LeftToRight, + Typeface, + size, + brush ?? DefaultColor, + dpiScale + ); + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Editor/ViewModel/EditorFrameViewModel.cs b/Qrakhen.Qamp.Editor/ViewModel/EditorFrameViewModel.cs index 00c51f5..91b603b 100644 --- a/Qrakhen.Qamp.Editor/ViewModel/EditorFrameViewModel.cs +++ b/Qrakhen.Qamp.Editor/ViewModel/EditorFrameViewModel.cs @@ -3,6 +3,7 @@ using Qrakhen.Qamp.Editor.Primitives; using Qrakhen.Qamp.Memory; using System; using System.Collections.ObjectModel; +using System.IO; using System.Windows.Documents; using System.Windows.Input; @@ -16,6 +17,12 @@ public class SelectableLineBuffer(LineBuffer buffer) public class EditorFrameViewModel : ObservableObject { + private FileInfo _fileInfo; + public FileInfo FileInfo { + get => _fileInfo; + set => SetProperty(ref _fileInfo, value); + } + private BufferPosition _cursorPosition; public BufferPosition CursorPosition { get => _cursorPosition; @@ -56,8 +63,6 @@ public class EditorFrameViewModel : ObservableObject ClipBoardCommand = new RelayCommand(() => { }); } - - public void SetCursor(int line, int column) => SetCursor(new BufferPosition(line, column)); public void SetCursor(BufferPosition position) { @@ -111,6 +116,20 @@ public class EditorFrameViewModel : ObservableObject } } + public void Select(BufferPosition relativePosition, bool jump = false) + { + if (CurrentSelection.IsVoid) { + CurrentSelection = new BufferRegion(CursorPosition, CursorPosition); + } + + CurrentSelection += relativePosition; + } + + public void Deselect() + { + CurrentSelection = BufferRegion.Void; + } + /* asdasdy diff --git a/Qrakhen.Qamp.Editor/ViewModel/MainViewModel.cs b/Qrakhen.Qamp.Editor/ViewModel/MainViewModel.cs index a4c5ea5..6b6c993 100644 --- a/Qrakhen.Qamp.Editor/ViewModel/MainViewModel.cs +++ b/Qrakhen.Qamp.Editor/ViewModel/MainViewModel.cs @@ -6,5 +6,5 @@ namespace Qrakhen.Qamp.Editor.ViewModel; public class MainViewModel { - + } diff --git a/Qrakhen.Qamp.Editor/ViewModel/ObservableObject.cs b/Qrakhen.Qamp.Editor/ViewModel/ObservableObject.cs index ab680d5..cf34745 100644 --- a/Qrakhen.Qamp.Editor/ViewModel/ObservableObject.cs +++ b/Qrakhen.Qamp.Editor/ViewModel/ObservableObject.cs @@ -6,20 +6,20 @@ namespace Qrakhen.Qamp.Editor.ViewModel; public abstract class ObservableObject : INotifyPropertyChanged { - public event PropertyChangedEventHandler? PropertyChanged; + public event PropertyChangedEventHandler? PropertyChanged; - protected bool SetProperty([NotNullIfNotNull("newValue")] ref T field, T newValue, [CallerMemberName] string? propertyName = null) - { - if (EqualityComparer.Default.Equals(field, newValue)) - return false; + protected bool SetProperty([NotNullIfNotNull("newValue")] ref T field, T newValue, [CallerMemberName] string? propertyName = null) + { + if (EqualityComparer.Default.Equals(field, newValue)) + return false; - field = newValue; - OnPropertyChanged(propertyName); - return true; - } + field = newValue; + OnPropertyChanged(propertyName); + return true; + } - protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } + protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Memory/LineBuffer.cs b/Qrakhen.Qamp.Memory/LineBuffer.cs index 8f8af5c..0489e84 100644 --- a/Qrakhen.Qamp.Memory/LineBuffer.cs +++ b/Qrakhen.Qamp.Memory/LineBuffer.cs @@ -31,32 +31,32 @@ public struct BufferSpan public class LineBuffer : TailBuffer, INotifyPropertyChanged { - public Encoding Encoding { get; } - public string Cached { get; private set; } = ""; - public event PropertyChangedEventHandler? PropertyChanged; + public Encoding Encoding { get; } + public string Cached { get; private set; } = ""; + public event PropertyChangedEventHandler? PropertyChanged; - public LineBuffer(Encoding encoding, int size = 0x80) : base(size) - { - Encoding = encoding; - } + public LineBuffer(Encoding encoding, int size = 0x80) : base(size) + { + Encoding = encoding; + } - public LineBuffer(string data) : this(data, Encoding.ASCII) { } - public LineBuffer(string data, Encoding encoding) : this(encoding.GetBytes(data), encoding) { } - public LineBuffer(byte[] data, Encoding encoding) : base(data) - { - Encoding = encoding; - Cached = ToString(); - } + public LineBuffer(string data) : this(data, Encoding.ASCII) { } + public LineBuffer(string data, Encoding encoding) : this(encoding.GetBytes(data), encoding) { } + public LineBuffer(byte[] data, Encoding encoding) : base(data) + { + Encoding = encoding; + Cached = ToString(); + } - protected override void SetTail(int tail = -1) - { - base.SetTail(tail); - Cached = ToString(); - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Cached))); - } + protected override void SetTail(int tail = -1) + { + base.SetTail(tail); + Cached = ToString(); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Cached))); + } - public void Insert(int cursor, string data) - => Insert(cursor, Encoding.GetBytes(data)); + public void Insert(int cursor, string data) + => Insert(cursor, Encoding.GetBytes(data)); public string ToString(BufferSpan span) { @@ -66,17 +66,17 @@ public class LineBuffer : TailBuffer, INotifyPropertyChanged return Encoding.GetString(Data[synced.Start..synced.End]); } - public override string ToString() - { - if (Tail == 0 || Encoding == null) - return string.Empty; - return Encoding.GetString(Data, 0, Tail); - } + public override string ToString() + { + if (Tail == 0 || Encoding == null) + return string.Empty; + return Encoding.GetString(Data, 0, Tail); + } - public override object Clone() - { - return new LineBuffer(_data.ToArray(), Encoding); - } + public override object Clone() + { + return new LineBuffer(_data.ToArray(), Encoding); + } - public static implicit operator LineBuffer(string s) => new LineBuffer(s); + public static implicit operator LineBuffer(string s) => new LineBuffer(s); } diff --git a/Qrakhen.Qamp.Memory/TailBuffer.cs b/Qrakhen.Qamp.Memory/TailBuffer.cs index 875edfb..c0b670d 100644 --- a/Qrakhen.Qamp.Memory/TailBuffer.cs +++ b/Qrakhen.Qamp.Memory/TailBuffer.cs @@ -3,87 +3,87 @@ // add to qrakhen.memory package for clout public abstract class TailBuffer : ICloneable { - protected T[] _data; - public T[] Data { - get => _data; - } + protected T[] _data; + public T[] Data { + get => _data; + } - public int Capacity => _data.Length; - public int Tail { get; private set; } + public int Capacity => _data.Length; + public int Tail { get; private set; } - public TailBuffer(int size = 0x80) - { - _data = new T[size]; - } + public TailBuffer(int size = 0x80) + { + _data = new T[size]; + } - public TailBuffer(T[] data) - { - _data = new T[Math.Max(0x10, data.Length * 2)]; - Array.Copy(data, 0, _data, 0, data.Length); - SetTail(data.Length); - } + public TailBuffer(T[] data) + { + _data = new T[Math.Max(0x10, data.Length * 2)]; + Array.Copy(data, 0, _data, 0, data.Length); + SetTail(data.Length); + } - public void Insert(int cursor, T[] data) - { - cursor = SeekTail(cursor); - Prepare(cursor, data.Length); - int length = data.Length; - if (cursor == Tail) { - // Just append here. - Array.Copy(data, 0, _data, cursor, length); - SetTail(cursor + length); - } else { - // Shift everything to the right of insertion - Array.Copy(_data, cursor, _data, cursor + length, Tail - cursor); - Array.Copy(data, 0, _data, cursor, length); - SetTail(Tail + length); - } - } + public void Insert(int cursor, T[] data) + { + cursor = SeekTail(cursor); + Prepare(cursor, data.Length); + int length = data.Length; + if (cursor == Tail) { + // Just append here. + Array.Copy(data, 0, _data, cursor, length); + SetTail(cursor + length); + } else { + // Shift everything to the right of insertion + Array.Copy(_data, cursor, _data, cursor + length, Tail - cursor); + Array.Copy(data, 0, _data, cursor, length); + SetTail(Tail + length); + } + } - public void Delete(Range range) - => Delete(range.From, range.To - range.From); + public void Delete(Range range) + => Delete(range.From, range.To - range.From); - public void Delete(int cursor, int count) - { - if (cursor + count >= Tail) - SetTail(cursor); // Directly terminate at cursor, nothing is behind tail. - else { - // Move everything from end of deletion until tail to start of deletion. - Array.Copy(_data, cursor + count, _data, cursor, Tail - (cursor + count)); - SetTail(Tail - count); - } - } + public void Delete(int cursor, int count) + { + if (cursor + count >= Tail) + SetTail(cursor); // Directly terminate at cursor, nothing is behind tail. + else { + // Move everything from end of deletion until tail to start of deletion. + Array.Copy(_data, cursor + count, _data, cursor, Tail - (cursor + count)); + SetTail(Tail - count); + } + } - public T[] Slice(int from = 0, int until = -1) - { - from = SeekTail(from); - if (from == Tail) - return []; - until = until < 0 ? Tail : SeekTail(until); - T[] data = _data[from..until]; - Delete(from, until - from); - return data; - } + public T[] Slice(int from = 0, int until = -1) + { + from = SeekTail(from); + if (from == Tail) + return []; + until = until < 0 ? Tail : SeekTail(until); + T[] data = _data[from..until]; + Delete(from, until - from); + return data; + } - public abstract object Clone(); + public abstract object Clone(); - // never write beyond tail (there might be invalid data) - private int SeekTail(int cursor) => Math.Max(0, Math.Min(cursor, Tail)); + // never write beyond tail (there might be invalid data) + private int SeekTail(int cursor) => Math.Max(0, Math.Min(cursor, Tail)); - private void Prepare(int index, int count) - { - ArgumentOutOfRangeException.ThrowIfNegative(index); - if (count + Tail <= _data.Length) - return; - while (count + Tail > _data.Length) { - T[] grow = new T[_data.Length * 2]; - Array.Copy(_data, grow, _data.Length); - _data = grow; - } - } + private void Prepare(int index, int count) + { + ArgumentOutOfRangeException.ThrowIfNegative(index); + if (count + Tail <= _data.Length) + return; + while (count + Tail > _data.Length) { + T[] grow = new T[_data.Length * 2]; + Array.Copy(_data, grow, _data.Length); + _data = grow; + } + } - protected virtual void SetTail(int tail) - { - Tail = tail; - } + protected virtual void SetTail(int tail) + { + Tail = tail; + } } diff --git a/Qrakhen.Qamp.Tests/UnitTest1.cs b/Qrakhen.Qamp.Tests/UnitTest1.cs index 02fe1af..db478c6 100644 --- a/Qrakhen.Qamp.Tests/UnitTest1.cs +++ b/Qrakhen.Qamp.Tests/UnitTest1.cs @@ -2,9 +2,9 @@ namespace Qrakhen.Qamp.Tests; public class UnitTest1 { - [Fact] - public void Test1() - { + [Fact] + public void Test1() + { - } + } } \ No newline at end of file