diff --git a/Qrakhen.Qamp.CLI/ConsoleCode.cs b/Qrakhen.Qamp.CLI/ConsoleCode.cs new file mode 100644 index 0000000..60fee39 --- /dev/null +++ b/Qrakhen.Qamp.CLI/ConsoleCode.cs @@ -0,0 +1,6 @@ +public enum ConsoleCode +{ + Error = -1, + OK = 0, + Exit = 1 +} diff --git a/Qrakhen.Qamp.CLI/ConsoleExtensions.cs b/Qrakhen.Qamp.CLI/ConsoleExtensions.cs new file mode 100644 index 0000000..39a053c --- /dev/null +++ b/Qrakhen.Qamp.CLI/ConsoleExtensions.cs @@ -0,0 +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); + } +} \ No newline at end of file diff --git a/Qrakhen.Qamp.CLI/ConsoleRenderer.cs b/Qrakhen.Qamp.CLI/ConsoleRenderer.cs new file mode 100644 index 0000000..0196dbd --- /dev/null +++ b/Qrakhen.Qamp.CLI/ConsoleRenderer.cs @@ -0,0 +1,58 @@ + +using Qrakhen.Qamp.Core; +using Qrakhen.Qamp.Core.Tokenization; +using System.Text; + +public class ConsoleRenderer +{ + 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 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.Magenta; + 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 new file mode 100644 index 0000000..0693014 --- /dev/null +++ b/Qrakhen.Qamp.CLI/ConsoleWriter.cs @@ -0,0 +1,142 @@ +using System.Text; + +public class ConsoleWriter +{ + private const string SYMBOL_INPUT = " <: "; + private const string SYMBOL_INPUT_CONTINUE = " : "; + + 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 _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 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 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 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); + } + } + 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; + } + + 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 12a7b63..d6e85ad 100644 --- a/Qrakhen.Qamp.CLI/Program.cs +++ b/Qrakhen.Qamp.CLI/Program.cs @@ -1,19 +1,20 @@  using Qrakhen.Qamp.Core; using Qrakhen.Qamp.Core.Execution; -using Qrakhen.Qamp.Core.Tokenization; +using Qrakhen.Qamp.Core.Logging; using System.Text; char[] Ignored = [ '\0', '\b' ]; +LoggerService.Default = LogLevel.Error; Stack History = []; ConsoleKeyInfo input; bool useSyntaxHighlighting = false; (int x, int y) cursor = (0, 0); ConsoleCode code = ConsoleCode.Error; Runner runner = new Runner(new Options()); -ConsoleInterface cli = new ConsoleInterface(Encoding.Default); +ConsoleWriter cli = new ConsoleWriter(Encoding.Default); do { - /*Console.ForegroundColor = ConsoleColor.White; + Console.ForegroundColor = ConsoleColor.White; MemoryStream stream = new MemoryStream(); Console.Write(" <: "); cursor = Console.GetCursorPosition(); @@ -28,6 +29,11 @@ do { 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; } @@ -64,17 +70,10 @@ do { Console.Write(input.KeyChar); stream.Insert(Encoding.Default.GetBytes([input.KeyChar], 0, 1)); } - } while (input.Key != ConsoleKey.Enter || input.Modifiers == ConsoleModifiers.Shift);*/ + } while (input.Key != ConsoleKey.Enter || input.Modifiers == ConsoleModifiers.Shift); 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}"); + Console.WriteLine(); + runner.Run(stream); } catch (QampException e) { Console.ForegroundColor = ConsoleColor.Yellow; @@ -93,216 +92,3 @@ do { } } } while(code != ConsoleCode.Exit); - -class ConsoleInterface -{ - private const string SYMBOL_INPUT = " <: "; - private const string SYMBOL_INPUT_CONTINUE = " : "; - - 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 _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 ConsoleInterface(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 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 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); - } - } - 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; - } - - 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; - } -} - -enum ConsoleCode -{ - Error = -1, - OK = 0, - Exit = 1 -} - -class ConsoleRenderer -{ - 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 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.Red; - if (token.Type.IsNumber()) - color = ConsoleColor.DarkCyan; - if (token.Type.IsOperator()) - color = ConsoleColor.DarkGreen; - if (token.Type.IsBracket()) - color = ConsoleColor.Yellow; - 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 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); - } -} \ No newline at end of file diff --git a/Qrakhen.Qamp.CLI/_Program.cs b/Qrakhen.Qamp.CLI/_Program.cs new file mode 100644 index 0000000..492ceb8 --- /dev/null +++ b/Qrakhen.Qamp.CLI/_Program.cs @@ -0,0 +1,43 @@ + +using Qrakhen.Qamp.Core; +using Qrakhen.Qamp.Core.Execution; +using Qrakhen.Qamp.Core.Tokenization; +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'))); + } + } + } while (code != ConsoleCode.Exit); + } +} diff --git a/Qrakhen.Qamp.Core/Collections/Pointer.cs b/Qrakhen.Qamp.Core/Collections/Pointer.cs index bac7541..780c0e2 100644 --- a/Qrakhen.Qamp.Core/Collections/Pointer.cs +++ b/Qrakhen.Qamp.Core/Collections/Pointer.cs @@ -6,7 +6,7 @@ public class Pointer { protected IGetSet Target; - public long Ptr; + public long Cursor; public T Current { get => Get(); @@ -16,41 +16,41 @@ public class Pointer public Pointer(IGetSet target, long pointer = 0) { Target = target; - Ptr = pointer; + Cursor = pointer; } public Pointer Branch(long delta = 0) { - return new Pointer(Target, Ptr + delta); + return new Pointer(Target, Cursor + delta); } /// /// Returns the next item from and increases the pointer by 1. /// - public T Next() => Target.Get(Ptr++); + public T Next() => Target.Get(Cursor++); /// - /// Sets the value of at . + /// Sets the value of RELATIVE from the current position (). /// - public void Set(long position, T value) => Target.Set(position, value); + public void Set(long delta, T value) => Target.Set(Cursor + delta, value); /// - /// Sets the value of at the current location. + /// Sets the value of at the current location. /// - public void Set(T value) => Set(Ptr, value); + public void Set(T value) => Set(Cursor, value); /// - /// Gets the value of at . + /// Gets the value of RELATIVE from the current position (). /// - public T Get(long position) => Target.Get(position); + public T Get(long delta) => Target.Get(Cursor + delta); /// - /// Gets the value of at the current location. + /// Gets the value of at the current location. /// - public T Get() => Get(Ptr); + public T Get() => Get(Cursor); public override string ToString() { - return $"&{Ptr:X4}={Current}"; + return $"&{Cursor:X4}={Current}"; } } diff --git a/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs b/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs index 47736aa..30a3cf8 100644 --- a/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs +++ b/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs @@ -241,6 +241,11 @@ public static class ExpressionParser } } + static void TypeOf(Digester digester, bool canAssign) + { + digester.TypeOf(); + } + static ExpressionParser() { _rules[TokenType.GroupOpen] = new Rule(Group, Call, Weight.Call); @@ -290,11 +295,11 @@ public static class ExpressionParser _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(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.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); diff --git a/Qrakhen.Qamp.Core/Execution/InstructionPtr.cs b/Qrakhen.Qamp.Core/Execution/InstructionPtr.cs index 968ad81..49b42e2 100644 --- a/Qrakhen.Qamp.Core/Execution/InstructionPtr.cs +++ b/Qrakhen.Qamp.Core/Execution/InstructionPtr.cs @@ -8,7 +8,7 @@ public class InstructionPtr : Pointer { public Segment Segment; - public Instruction Instruction => Segment.Instructions[Ptr]; + public Instruction Instruction => Segment.Instructions[Cursor]; public InstructionPtr(Segment segment, int position = 0) : base(segment.Instructions, position) { @@ -17,8 +17,8 @@ public class InstructionPtr : Pointer public long NextLong() { - long value = Segment.ReadLong(Ptr); - Ptr += sizeof(long); + long value = Segment.ReadLong(Cursor); + Cursor += sizeof(long); return value; } @@ -37,8 +37,8 @@ public class InstructionPtr : Pointer public long NextDynamic() { - var result = Segment.ReadDynamic(Ptr, out int read); - Ptr += read; + var result = Segment.ReadDynamic(Cursor, out int read); + Cursor += read; return result; } @@ -46,20 +46,20 @@ public class InstructionPtr : Pointer => Segment.Constants[offset].Ptr.Value as String; public static Instruction operator +(InstructionPtr ptr, int value) - => ptr.Segment.Instructions[ptr.Ptr + value]; + => ptr.Segment.Instructions[ptr.Cursor + value]; public static Instruction operator -(InstructionPtr ptr, int value) - => ptr.Segment.Instructions[ptr.Ptr - value]; + => ptr.Segment.Instructions[ptr.Cursor - value]; public static InstructionPtr operator ++(InstructionPtr ptr) { - ptr.Ptr++; + ptr.Cursor++; return ptr; } public static InstructionPtr operator --(InstructionPtr ptr) { - ptr.Ptr--; + ptr.Cursor--; return ptr; } } diff --git a/Qrakhen.Qamp.Core/Execution/Runner.cs b/Qrakhen.Qamp.Core/Execution/Runner.cs index a7e3e9d..e45982b 100644 --- a/Qrakhen.Qamp.Core/Execution/Runner.cs +++ b/Qrakhen.Qamp.Core/Execution/Runner.cs @@ -53,6 +53,10 @@ public class Runner : IDisposable public ExecutionResult Run(Stream stream) { _logger.Method(); + if (Stack.Position < 0) { + _logger.Warn($"Something went wrong, stack cursor is at {Stack.Position}. Resetting Stack."); + Stack.Decimate(0); + } using Reader reader = new Reader(stream); Compilation.Digester digester = new(reader); Function function = digester.Digest(); @@ -95,7 +99,7 @@ public class Runner : IDisposable case Op.GetGlobal: { string? name = call.Instruction.GetStringConstant(call.Instruction.NextDynamic())?.Value; if (string.IsNullOrEmpty(name)) - throw new RuntimeException($"tried to set global variable with empty name"); + return Error($"tried to set global variable with empty name"); if (!Globals.Has(name)) Push(Value.Void); else @@ -107,9 +111,9 @@ public class Runner : IDisposable case Op.SetGlobal: { string? name = call.Instruction.GetStringConstant(call.Instruction.NextDynamic())?.Value; if (string.IsNullOrEmpty(name)) - throw new RuntimeException($"tried to set global variable with empty name"); + return Error($"tried to set global variable with empty name"); if (!Globals.Has(name)) - throw new RuntimeException($"tried to set a value of non-existing global variable"); + return Error($"tried to set a value of non-existing global variable"); Globals[name] = Pop(); _logger.Verbose($"set global {name} = {Globals[name]}"); break; @@ -118,7 +122,7 @@ public class Runner : IDisposable case Op.DefineGlobal: { string? name = call.Instruction.GetStringConstant(call.Instruction.NextDynamic())?.Value; if (string.IsNullOrEmpty(name)) - throw new RuntimeException($"tried to define global variable with empty name"); + return Error($"tried to define global variable with empty name"); Globals[name] = Pop(); _logger.Verbose($"defined global {name} as {Globals[name]}"); break; @@ -189,20 +193,20 @@ public class Runner : IDisposable case Op.Jump: { long delta = call.Instruction.NextLong(); - call.Instruction.Ptr += delta; + call.Instruction.Cursor += delta; break; } case Op.JumpIfFalse: { long delta = call.Instruction.NextLong(); if (Peek().IsFalsy) - call.Instruction.Ptr += delta; + call.Instruction.Cursor += delta; break; } case Op.Loop: { long delta = call.Instruction.NextLong(); - call.Instruction.Ptr -= delta; + call.Instruction.Cursor -= delta; break; } @@ -263,7 +267,7 @@ public class Runner : IDisposable Pop(); return ExecutionResult.OK; } - Stack.Decimate(call.StackPtr.Ptr); + Stack.Decimate(call.StackPtr.Cursor); Push(result); call = Calls.Peek(); break; @@ -293,7 +297,18 @@ public class Runner : IDisposable case Op.Typeof: { Value value = Pop(); - Push(String.Make(value.Type.ToString())); + 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; } @@ -321,7 +336,7 @@ public class Runner : IDisposable return Error($"Unexpected or not yet supported OpCode {opCode}!"); } - } while (call.Instruction.Segment.Instructions.Length > call.Instruction.Ptr); + } while (call.Instruction.Segment.Instructions.Length > call.Instruction.Cursor); return ExecutionResult.OK; } @@ -331,11 +346,11 @@ public class Runner : IDisposable Outer? outer = null; for (int i = Outers.Count; i-->0;) { outer = Outers[i]; - if (outer.Target.Ptr <= target.Ptr) + if (outer.Target.Cursor <= target.Cursor) break; } - if (outer != null && outer.Target.Ptr == target.Ptr) + if (outer != null && outer.Target.Cursor == target.Cursor) return outer; return new Outer(target); @@ -347,7 +362,7 @@ public class Runner : IDisposable Outer outer = Outers[i]; if (outer.IsClosed) continue; - if (outer.Target.Ptr < last.Ptr) + if (outer.Target.Cursor < last.Cursor) return; outer.Close(); } @@ -356,11 +371,15 @@ public class Runner : IDisposable private bool Invoke(Context closure, int argumentCount) { _logger.Method(); - if (argumentCount != closure.Function.ArgumentCount) - throw new Exception($"Expected {closure.Function.ArgumentCount} arguments but got {argumentCount}"); - - if (Calls.Count > Options.MaxCalls) - throw new StackOverflowException($"Stack overflow {Calls.Count}"); + 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); @@ -369,7 +388,7 @@ public class Runner : IDisposable private bool Invoke(string methodName, int argumentCount) { - Value value = Peek(-argumentCount); + Value value = Peek(-argumentCount - 1); if (!value.Is(T.Instance)) { Error($"Can not call {methodName} on value of {value}"); return false; @@ -430,7 +449,7 @@ public class Runner : IDisposable return false; } - Method method = new Method(value.Ptr.As()!, Peek()); + Method method = new Method(value.Ptr.As()!.Function, Peek()); Pop(); // remove instance from stack Push(Obj.Create(method)); return true; @@ -483,11 +502,18 @@ public class Runner : IDisposable { _logger.Method(message); _logger.Error(message, context); + Panic(); if (@throw) throw new QampException(message, context); return ExecutionResult.Execution; } + private void Panic() + { + _logger.Method(); + Stack.Decimate(0); + } + public void Dispose() { _logger.Method(); diff --git a/Qrakhen.Qamp.Core/Logging/ILogger.cs b/Qrakhen.Qamp.Core/Logging/ILogger.cs index cc4cdc3..5e9c08e 100644 --- a/Qrakhen.Qamp.Core/Logging/ILogger.cs +++ b/Qrakhen.Qamp.Core/Logging/ILogger.cs @@ -75,7 +75,8 @@ public class LoggerService public class Logger : ILogger, ILogFormatter { public string Name { get; private set; } - public LogLevel Level { get; set; } + private LogLevel _level; + public LogLevel Level { get => true ? LoggerService.Default : _level; set => _level = value; } private static Dictionary headers = new() { { LogLevel.Critical, (" !? ", " !? ") }, diff --git a/Qrakhen.Qamp.Core/Values/Objects/Class.cs b/Qrakhen.Qamp.Core/Values/Objects/Class.cs index 34f2b59..0276c74 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Class.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Class.cs @@ -4,4 +4,9 @@ public class Class(string name) : Obj(ValueType.Class) { public readonly string Name = name; public Table Members = new(); + + public override string ToString() + { + return $"{Name} (Class)"; + } } diff --git a/Qrakhen.Qamp.Core/Values/Objects/Instance.cs b/Qrakhen.Qamp.Core/Values/Objects/Instance.cs index e78daa8..afa23ef 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Instance.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Instance.cs @@ -4,4 +4,16 @@ public class Instance(Class @class) : Obj(ValueType.Instance) { 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}}}"; + } }