fix a few issues, split CLI classes, fix member calls

This commit is contained in:
Qrakhen 2025-11-09 09:33:08 +01:00
parent 1c161bfda4
commit 0e11be061b
13 changed files with 365 additions and 271 deletions

View File

@ -0,0 +1,6 @@
public enum ConsoleCode
{
Error = -1,
OK = 0,
Exit = 1
}

View File

@ -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);
}
}

View File

@ -0,0 +1,58 @@

using Qrakhen.Qamp.Core;
using Qrakhen.Qamp.Core.Tokenization;
using System.Text;
public class ConsoleRenderer
{
private readonly IReader<Token> _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<Token> 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;
}
}

View File

@ -0,0 +1,142 @@
using System.Text;
public class ConsoleWriter
{
private const string SYMBOL_INPUT = " <: ";
private const string SYMBOL_INPUT_CONTINUE = " : ";
private readonly List<char> _buffer = [];
private readonly Stack<char[]> _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;
}
}

View File

@ -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<byte[]> 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,18 +70,11 @@ 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}");
}
catch (QampException e) {
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($" !> {e.Message}");
@ -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<char> _buffer = [];
private readonly Stack<char[]> _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<Token> _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<Token> 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);
}
}

View File

@ -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);
}
}

View File

@ -6,7 +6,7 @@
public class Pointer<T>
{
protected IGetSet<long, T> Target;
public long Ptr;
public long Cursor;
public T Current {
get => Get();
@ -16,41 +16,41 @@ public class Pointer<T>
public Pointer(IGetSet<long, T> target, long pointer = 0)
{
Target = target;
Ptr = pointer;
Cursor = pointer;
}
public Pointer<T> Branch(long delta = 0)
{
return new Pointer<T>(Target, Ptr + delta);
return new Pointer<T>(Target, Cursor + delta);
}
/// <summary>
/// Returns the next item from <see cref="Target"/> and increases the pointer by 1.
/// </summary>
public T Next() => Target.Get(Ptr++);
public T Next() => Target.Get(Cursor++);
/// <summary>
/// Sets the value of <see cref="Target"/> at <paramref name="position"/>.
/// Sets the value of <see cref="Target"/> RELATIVE from the current position (<paramref name="delta"/>).
/// </summary>
public void Set(long position, T value) => Target.Set(position, value);
public void Set(long delta, T value) => Target.Set(Cursor + delta, value);
/// <summary>
/// Sets the value of <see cref="Target"/> at the current <see cref="Ptr"/> location.
/// Sets the value of <see cref="Target"/> at the current <see cref="Cursor"/> location.
/// </summary>
public void Set(T value) => Set(Ptr, value);
public void Set(T value) => Set(Cursor, value);
/// <summary>
/// Gets the value of <see cref="Target"/> at <paramref name="position"/>.
/// Gets the value of <see cref="Target"/> RELATIVE from the current position (<paramref name="delta"/>).
/// </summary>
public T Get(long position) => Target.Get(position);
public T Get(long delta) => Target.Get(Cursor + delta);
/// <summary>
/// Gets the value of <see cref="Target"/> at the current <see cref="Ptr"/> location.
/// Gets the value of <see cref="Target"/> at the current <see cref="Cursor"/> location.
/// </summary>
public T Get() => Get(Ptr);
public T Get() => Get(Cursor);
public override string ToString()
{
return $"&{Ptr:X4}={Current}";
return $"&{Cursor:X4}={Current}";
}
}

View File

@ -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,7 +295,7 @@ 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);

View File

@ -8,7 +8,7 @@ public class InstructionPtr : Pointer<Instruction>
{
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<Instruction>
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<Instruction>
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<Instruction>
=> 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;
}
}

View File

@ -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<Class>()!.Name;
else if (value.Is(T.Instance))
type = $"instance of {value.Ptr.As<Instance>()!.Class.Name}";
else if (value.Is(T.Function))
type = $"function {value.Ptr.As<Function>()!.Name}";
else if (value.Is(T.Method))
type = $"method {value.Ptr.As<Method>()!.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 (argumentCount != closure.Function.ArgumentCount) {
Error($"Expected {closure.Function.ArgumentCount} arguments but got {argumentCount}");
return false;
}
if (Calls.Count > Options.MaxCalls)
throw new StackOverflowException($"Stack overflow {Calls.Count}");
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<Function>()!, Peek());
Method method = new Method(value.Ptr.As<Context>()!.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();

View File

@ -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<LogLevel, (string First, string Extra)> headers = new() {
{ LogLevel.Critical, (" !? ", " !? ") },

View File

@ -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)";
}
}

View File

@ -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}}}";
}
}