diff --git a/Qrakhen.Qamp.Core/Collections/Pointer.cs b/Qrakhen.Qamp.Core/Collections/Pointer.cs index 1229797..bac7541 100644 --- a/Qrakhen.Qamp.Core/Collections/Pointer.cs +++ b/Qrakhen.Qamp.Core/Collections/Pointer.cs @@ -8,6 +8,11 @@ public class Pointer protected IGetSet Target; public long Ptr; + public T Current { + get => Get(); + set => Set(value); + } + public Pointer(IGetSet target, long pointer = 0) { Target = target; @@ -43,4 +48,9 @@ public class Pointer /// Gets the value of at the current location. /// public T Get() => Get(Ptr); + + public override string ToString() + { + return $"&{Ptr:X4}={Current}"; + } } diff --git a/Qrakhen.Qamp.Core/Compilation/Builders/Builder.cs b/Qrakhen.Qamp.Core/Compilation/Builders/Builder.cs index e242c9c..b54d7df 100644 --- a/Qrakhen.Qamp.Core/Compilation/Builders/Builder.cs +++ b/Qrakhen.Qamp.Core/Compilation/Builders/Builder.cs @@ -6,13 +6,15 @@ public class Builder { public Builder? Outer { get; init; } public FunctionBuilder Function = new(); + public readonly FunctionType Type; public StackLike Locals = []; public StackLike Outers = []; public int ScopeDepth = 0; - public Builder(Builder? outer = null) + 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/SegmentBuilder.cs b/Qrakhen.Qamp.Core/Compilation/Builders/SegmentBuilder.cs index a2da2aa..d0642bb 100644 --- a/Qrakhen.Qamp.Core/Compilation/Builders/SegmentBuilder.cs +++ b/Qrakhen.Qamp.Core/Compilation/Builders/SegmentBuilder.cs @@ -20,13 +20,13 @@ public class SegmentBuilder() : IBuilder, IDebug for (int i = 0; i < Instructions.Count; i++) { var instruction = Instructions[i]; - if ((instruction.Code & 0x80) == 1) { + /*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 + } else*/ str += $"\n [{i:x4}]: {instruction}".PadRight(32); /*if (instruction.OpCode == OpCode.Constant) { i++; // i know, i know diff --git a/Qrakhen.Qamp.Core/Compilation/Digester.cs b/Qrakhen.Qamp.Core/Compilation/Digester.cs index 0440924..137265b 100644 --- a/Qrakhen.Qamp.Core/Compilation/Digester.cs +++ b/Qrakhen.Qamp.Core/Compilation/Digester.cs @@ -13,7 +13,7 @@ namespace Qrakhen.Qamp.Core.Compilation; public record struct Local(string Name, int Depth = -1, bool IsCaptured = false); public record struct Outer(long Index, bool IsLocal); -public enum FunctionType { Function, Constructor, Method, Script } +public enum FunctionType { Function, Constructor, Method, Code } internal class CompilerState { @@ -69,7 +69,7 @@ public class Digester : ISteppable public Digester(IReader reader) { - Builder = CreateBuilder(FunctionType.Script); + Builder = CreateBuilder(FunctionType.Code); _reader = reader; } @@ -88,17 +88,18 @@ public class Digester : ISteppable Process(); } + SegmentBuilder _debug = Builder.Function.Segment; + Function function = FinishBuilder(); _logger.Debug($"Digest done, instruction set:"); - _logger.Verbose(Builder.Function.Segment.Debug()); - - return Function.Build(); + _logger.Verbose(_debug.Debug()); + return function; } internal Builder CreateBuilder(FunctionType type) { - Builder builder = new() { Outer = Builder }; + Builder builder = new(type, Builder); - if (type != FunctionType.Script) + if (type != FunctionType.Code) builder.Function.Name = Previous.Value!; builder.Locals.Push(new Local(type == FunctionType.Function ? "" : "this", 0)); @@ -108,7 +109,7 @@ public class Digester : ISteppable internal Function FinishBuilder() { - Emit(Op.Return); + EmitReturn(); Function function = Builder.Function.Build(); Builder = Builder.Outer; return function; @@ -382,7 +383,23 @@ public class Digester : ISteppable internal void Return() { _logger.Method(); - Emit(Op.Return); + 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; + } + + ParseExpression(); + Consume(T.Semicolon, $"Expected ';' after return."); + Emit(Op.Return); + } } internal void Print() @@ -635,7 +652,7 @@ public class Digester : ISteppable internal void PatchJump(long offset) { - long target = CurrentInstruction - (offset - sizeof(long)); + long target = CurrentInstruction - offset - sizeof(long); Patch(target.GetBytes(), offset); } @@ -685,6 +702,17 @@ public class Digester : ISteppable Emit(i); } + internal void EmitReturn() + { + if (Builder.Type == FunctionType.Constructor) { + Emit(Op.GetLocal, 0); + } else { + Emit(Op.Null); + } + + Emit(Op.Return); + } + internal void Emit(params Instruction[] instructions) => Emit(instructions.AsEnumerable()); diff --git a/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs b/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs index a0d58d5..47736aa 100644 --- a/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs +++ b/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs @@ -108,7 +108,7 @@ public static class ExpressionParser break; } digester.Consume(TokenType.ArrayClose, "Expected ']' after array definition"); - digester.EmitDynamic(OpCode.Array, digester.MakeConstant(new Value((long)length))); + digester.EmitDynamic(OpCode.Array, length); // digester.MakeConstant(new Value((long)length))); } static void ArrayAdd(Digester digester, bool canAssign) diff --git a/Qrakhen.Qamp.Core/Execution/Instruction.cs b/Qrakhen.Qamp.Core/Execution/Instruction.cs index 66aefd6..0bca50f 100644 --- a/Qrakhen.Qamp.Core/Execution/Instruction.cs +++ b/Qrakhen.Qamp.Core/Execution/Instruction.cs @@ -11,8 +11,6 @@ public readonly record struct Instruction(byte Code) public override string ToString() { - if ((Code & 0x80) == 0x80) - return $""; - return $"<{OpCode} ({Code})>"; + return $"<{Code:X4} | {OpCode}>"; } } \ No newline at end of file diff --git a/Qrakhen.Qamp.Core/Execution/Runner.cs b/Qrakhen.Qamp.Core/Execution/Runner.cs index d99931d..a7e3e9d 100644 --- a/Qrakhen.Qamp.Core/Execution/Runner.cs +++ b/Qrakhen.Qamp.Core/Execution/Runner.cs @@ -86,6 +86,7 @@ public class Runner : IDisposable } 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; @@ -194,7 +195,7 @@ public class Runner : IDisposable case Op.JumpIfFalse: { long delta = call.Instruction.NextLong(); - if (Peek(0).IsFalsy) + if (Peek().IsFalsy) call.Instruction.Ptr += delta; break; } @@ -361,7 +362,7 @@ public class Runner : IDisposable if (Calls.Count > Options.MaxCalls) throw new StackOverflowException($"Stack overflow {Calls.Count}"); - Call call = new(closure, Stack, Stack.Position - argumentCount); + Call call = new(closure, Stack, Cursor - argumentCount - 1); Calls.Push(call); return true; } diff --git a/Qrakhen.Qamp.Core/Values/Objects/Context.cs b/Qrakhen.Qamp.Core/Values/Objects/Context.cs index c7a7bf7..5c39d62 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Context.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Context.cs @@ -7,5 +7,5 @@ public class Context(Function function, ValueType type = ValueType.Context) : Ob public Function Function = function; public PushStack Outers = new(); - public override string ToString() => "{}"; + public override string ToString() => $"{Function.Name}(){{}}"; } \ No newline at end of file