implement dynamic reading everywhere, add method rendering and super calls
This commit is contained in:
parent
da653b3ce5
commit
5d17059a7a
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
public class ClassBuilder
|
public class ClassBuilder
|
||||||
{
|
{
|
||||||
|
public string Name;
|
||||||
|
|
||||||
public ClassBuilder? Outer;
|
public ClassBuilder? Outer;
|
||||||
public bool IsDerived;
|
public bool IsDerived;
|
||||||
}
|
}
|
||||||
|
|
@ -13,16 +13,23 @@ namespace Qrakhen.Qamp.Core.Compilation;
|
||||||
|
|
||||||
public record struct Local(string Name, int Depth = -1, bool IsCaptured = false);
|
public record struct Local(string Name, int Depth = -1, bool IsCaptured = false);
|
||||||
public record struct Outer(long Index, bool IsLocal);
|
public record struct Outer(long Index, bool IsLocal);
|
||||||
public enum FunctionType { Function, Init, Method, Script }
|
public enum FunctionType { Function, Constructor, Method, Script }
|
||||||
|
|
||||||
public class Compiler
|
internal class CompilerState
|
||||||
{
|
{
|
||||||
// could contain state like tokens, function builder, etc. and then IDigesters use that compiler state. smart, innit?
|
public readonly IReader<Token> Reader;
|
||||||
private readonly ILogger _logger = LoggerService.Get<Compiler>();
|
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;
|
||||||
|
|
||||||
private readonly PopStack<Token> _stack;
|
public bool ThrowOnError { get; set; } = true;
|
||||||
|
|
||||||
internal Builder Builder { get; private set; }
|
public Builder Builder;
|
||||||
|
public FunctionBuilder Function => Builder.Function;
|
||||||
|
public long CurrentInstruction => Function.Segment.Instructions.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DigesterProvider
|
public class DigesterProvider
|
||||||
|
|
@ -32,7 +39,7 @@ public class DigesterProvider
|
||||||
|
|
||||||
public class Digester : ISteppable<Token>
|
public class Digester : ISteppable<Token>
|
||||||
{
|
{
|
||||||
private readonly Compiler _compiler;
|
private readonly CompilerState _compiler;
|
||||||
|
|
||||||
public event Action<Token, string>? Error;
|
public event Action<Token, string>? Error;
|
||||||
|
|
||||||
|
|
@ -44,8 +51,8 @@ public class Digester : ISteppable<Token>
|
||||||
internal Token Current;
|
internal Token Current;
|
||||||
internal Token Previous;
|
internal Token Previous;
|
||||||
|
|
||||||
public ClassBuilder? Class { get; private set; }
|
|
||||||
public Builder Builder { get; private set; }
|
public Builder Builder { get; private set; }
|
||||||
|
public ClassBuilder? ClassBuilder { get; private set; }
|
||||||
public bool ThrowOnError { get; set; } = true;
|
public bool ThrowOnError { get; set; } = true;
|
||||||
|
|
||||||
public bool HadError => !ErrorPosition.IsNone;
|
public bool HadError => !ErrorPosition.IsNone;
|
||||||
|
|
@ -84,9 +91,7 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal Builder CreateBuilder(FunctionType type)
|
internal Builder CreateBuilder(FunctionType type)
|
||||||
{
|
{
|
||||||
Builder builder = new() {
|
Builder builder = new() { Outer = Builder };
|
||||||
Outer = Builder
|
|
||||||
};
|
|
||||||
|
|
||||||
if (type != FunctionType.Script)
|
if (type != FunctionType.Script)
|
||||||
builder.Function.Name = Previous.Value!;
|
builder.Function.Name = Previous.Value!;
|
||||||
|
|
@ -109,8 +114,8 @@ public class Digester : ISteppable<Token>
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
if (Match(T.Class)) DeclareClass();
|
if (Match(T.Class)) DeclareClass();
|
||||||
else if (Match(T.Function)) DeclareFunction();
|
else if (Match(T.Function)) DeclareFunction();
|
||||||
else if (Match(T.Var)) DeclareVariable();
|
else if (Match(T.Var)) DeclareVariable();
|
||||||
else Statement();
|
else Statement();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Statement()
|
internal void Statement()
|
||||||
|
|
@ -126,7 +131,7 @@ public class Digester : ISteppable<Token>
|
||||||
else if (Match(T.Print)) Print();
|
else if (Match(T.Print)) Print();
|
||||||
else if (Match(T.Export)) Export();
|
else if (Match(T.Export)) Export();
|
||||||
else if (Match(T.Import)) Import();
|
else if (Match(T.Import)) Import();
|
||||||
else if (Match(T.ContextOpen)) CreateContext();
|
else if (Match(T.ContextOpen)) Context();
|
||||||
else StatementExpression();
|
else StatementExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,7 +148,7 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void Expression() => WeightedDigest(Weight.Assign);
|
internal void Expression() => WeightedDigest(Weight.Assign);
|
||||||
|
|
||||||
internal void CreateContext()
|
internal void Context()
|
||||||
{
|
{
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
BeginScope();
|
BeginScope();
|
||||||
|
|
@ -177,9 +182,8 @@ public class Digester : ISteppable<Token>
|
||||||
ExpressionParser.Get(Previous.Type).Infix?.Invoke(this, canAssign);
|
ExpressionParser.Get(Previous.Type).Infix?.Invoke(this, canAssign);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canAssign && Match(T.Equal)) {
|
if (canAssign && Match(T.Equal))
|
||||||
ErrorAtCurrent("Invalid assignment target");
|
ErrorAtCurrent("Invalid assignment target");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void DeclareClass()
|
internal void DeclareClass()
|
||||||
|
|
@ -189,12 +193,25 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void DeclareFunction()
|
internal void DeclareFunction()
|
||||||
{
|
{
|
||||||
|
_logger.Method();
|
||||||
long global = ParseVariable();
|
long global = ParseVariable();
|
||||||
InitializeLocal();
|
InitializeLocal();
|
||||||
CreateFunction(FunctionType.Function);
|
CreateFunction(FunctionType.Function);
|
||||||
DefineVariable(global);
|
DefineVariable(global);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void DeclareMethod()
|
||||||
|
{
|
||||||
|
_logger.Method();
|
||||||
|
Consume(T.Identifier, "Expected method name", false);
|
||||||
|
long name = IdentifierConstant(Previous.Value!);
|
||||||
|
FunctionType type = FunctionType.Method;
|
||||||
|
if (Previous.Value == ClassBuilder?.Name)
|
||||||
|
type = FunctionType.Constructor;
|
||||||
|
CreateFunction(type);
|
||||||
|
EmitDynamic(Op.Method, name);
|
||||||
|
}
|
||||||
|
|
||||||
internal void DeclareVariable()
|
internal void DeclareVariable()
|
||||||
{
|
{
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
|
@ -477,7 +494,7 @@ public class Digester : ISteppable<Token>
|
||||||
InitializeLocal();
|
InitializeLocal();
|
||||||
} else {
|
} else {
|
||||||
Emit(Op.DefineGlobal);
|
Emit(Op.DefineGlobal);
|
||||||
Emit(index);
|
EmitDynamic(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -496,16 +513,40 @@ public class Digester : ISteppable<Token>
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Primary Emit.
|
||||||
|
/// </summary>
|
||||||
|
internal void Emit(params byte[] data)
|
||||||
|
{
|
||||||
|
if (data.Length == 1)
|
||||||
|
_logger.Verbose($"Emitting {new Instruction(data[0])}");
|
||||||
|
else if (data.Length > 1)
|
||||||
|
_logger.Verbose($"Emitting {string.Join(' ', data)}");
|
||||||
|
foreach (var value in data)
|
||||||
|
Function.Segment.Instructions.Add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets instruction bytes at <paramref name="position"/>
|
||||||
|
/// </summary>
|
||||||
|
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)
|
internal void EmitConstant(Value constant)
|
||||||
{
|
{
|
||||||
Emit(Op.Constant);
|
Emit(Op.Constant);
|
||||||
Emit(MakeConstant(constant));
|
EmitDynamic(MakeConstant(constant));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal long EmitJump(Instruction instruction)
|
internal long EmitJump(Instruction instruction)
|
||||||
{
|
{
|
||||||
Emit(instruction);
|
Emit(instruction);
|
||||||
Emit(0L);
|
Emit(-1L);
|
||||||
return CurrentInstruction - sizeof(long);
|
return CurrentInstruction - sizeof(long);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -522,22 +563,27 @@ public class Digester : ISteppable<Token>
|
||||||
Emit(offset);
|
Emit(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Emits a dynamic range of bytes into the instruction set.
|
||||||
|
/// </summary>
|
||||||
internal void EmitDynamic(byte[] data)
|
internal void EmitDynamic(byte[] data)
|
||||||
{
|
{
|
||||||
Emit(data.Length | 0x80);
|
Emit((byte)(data.Length | 0x80));
|
||||||
Emit(data);
|
Emit(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Emit(params byte[] data)
|
/// <summary>
|
||||||
|
/// Emits the given <paramref name="instruction"/>, and then adds <paramref name="data"/> using <see cref="EmitDynamic(byte[])"/>.
|
||||||
|
/// </summary>
|
||||||
|
internal void EmitDynamic(Instruction instruction, long data)
|
||||||
{
|
{
|
||||||
if (data.Length == 1)
|
Emit(instruction);
|
||||||
_logger.Verbose($"Emitting {new Instruction(data[0])}");
|
EmitDynamic(data);
|
||||||
else if (data.Length > 1)
|
|
||||||
_logger.Verbose($"Emitting {string.Join(' ', data)}");
|
|
||||||
foreach (var value in data)
|
|
||||||
Function.Segment.Instructions.Add(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void EmitDynamic(long value)
|
||||||
|
=> EmitDynamic(value.GetDynamicBytes());
|
||||||
|
|
||||||
internal void Emit(Instruction instruction)
|
internal void Emit(Instruction instruction)
|
||||||
{
|
{
|
||||||
Emit(instruction.Code);
|
Emit(instruction.Code);
|
||||||
|
|
@ -555,13 +601,6 @@ public class Digester : ISteppable<Token>
|
||||||
Emit(i);
|
Emit(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Patch(byte[] bytes, long position)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < bytes.Length; i++) {
|
|
||||||
Function.Segment.Instructions[position + i] = bytes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void Emit(params Instruction[] instructions)
|
internal void Emit(params Instruction[] instructions)
|
||||||
=> Emit(instructions.AsEnumerable());
|
=> Emit(instructions.AsEnumerable());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Qrakhen.Qamp.Core.Compilation.Digesters;
|
namespace Qrakhen.Qamp.Core.Compilation.Digesters;
|
||||||
|
|
||||||
public interface IDigester
|
internal interface IDigester
|
||||||
{
|
{
|
||||||
void Digest(Compiler compiler);
|
void Digest(CompilerState state);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,13 +63,13 @@ public static class ExpressionParser
|
||||||
|
|
||||||
if (canAssign && digester.Match(TokenType.Equal)) {
|
if (canAssign && digester.Match(TokenType.Equal)) {
|
||||||
digester.Expression();
|
digester.Expression();
|
||||||
digester.Emit(OpCode.SetProperty, name.GetBytes());
|
digester.EmitDynamic(OpCode.SetProperty, name);
|
||||||
} else if (digester.Match(TokenType.GroupOpen)) {
|
} else if (digester.Match(TokenType.GroupOpen)) {
|
||||||
Byte argCount = 0; //argumentList();
|
Byte argCount = 0; //argumentList();
|
||||||
digester.Emit(OpCode.Invoke, name.GetBytes());
|
digester.Emit(OpCode.Invoke, name.GetBytes());
|
||||||
digester.Emit(argCount);
|
digester.EmitDynamic(argCount);
|
||||||
} else {
|
} else {
|
||||||
digester.Emit(OpCode.GetProperty, name.GetBytes());
|
digester.EmitDynamic(OpCode.GetProperty, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,12 +108,10 @@ public static class ExpressionParser
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
digester.Consume(TokenType.ArrayClose, "Expected ']' after array definition");
|
digester.Consume(TokenType.ArrayClose, "Expected ']' after array definition");
|
||||||
digester.Emit(
|
digester.EmitDynamic(OpCode.Array, digester.MakeConstant(new Value((long)length)));
|
||||||
OpCode.Array,
|
|
||||||
digester.MakeConstant(new Value((long)length)).GetBytes());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Add(Digester digester, bool canAssign)
|
static void ArrayAdd(Digester digester, bool canAssign)
|
||||||
{
|
{
|
||||||
digester.Expression();
|
digester.Expression();
|
||||||
digester.Emit(OpCode.ArrayAdd);
|
digester.Emit(OpCode.ArrayAdd);
|
||||||
|
|
@ -168,10 +166,9 @@ public static class ExpressionParser
|
||||||
digester.EmitConstant(Values.Objects.String.Make(digester.Previous.Value));
|
digester.EmitConstant(Values.Objects.String.Make(digester.Previous.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Variable(Digester digester, bool canAssign)
|
static void Variable(Digester digester, string name, bool canAssign)
|
||||||
{
|
{
|
||||||
OpCode Get, Set;
|
OpCode Get, Set;
|
||||||
string name = digester.Previous.Value!;
|
|
||||||
long variable = digester.ResolveLocal(digester.Builder, name);
|
long variable = digester.ResolveLocal(digester.Builder, name);
|
||||||
if (variable > -1) {
|
if (variable > -1) {
|
||||||
Get = OpCode.GetLocal;
|
Get = OpCode.GetLocal;
|
||||||
|
|
@ -188,21 +185,46 @@ public static class ExpressionParser
|
||||||
if (canAssign && digester.Match(TokenType.Equal)) {
|
if (canAssign && digester.Match(TokenType.Equal)) {
|
||||||
digester.Expression();
|
digester.Expression();
|
||||||
digester.Emit(Set);
|
digester.Emit(Set);
|
||||||
digester.Emit(variable);
|
digester.EmitDynamic(variable);
|
||||||
} else {
|
} else {
|
||||||
digester.Emit(Get);
|
digester.Emit(Get);
|
||||||
digester.Emit(variable);
|
digester.EmitDynamic(variable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Variable(Digester digester, bool canAssign)
|
||||||
|
{
|
||||||
|
Variable(digester, digester.Previous.Value!, canAssign);
|
||||||
|
}
|
||||||
|
|
||||||
static void Base(Digester digester, bool canAssign)
|
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.ArgumentList();
|
||||||
|
Variable(digester, "base", false);
|
||||||
|
digester.Emit(OpCode.BaseCall);
|
||||||
|
digester.Emit(arguments);
|
||||||
|
} else {
|
||||||
|
Variable(digester, "base", false);
|
||||||
|
digester.Emit(OpCode.Base);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void This(Digester digester, bool canAssign)
|
static void This(Digester digester, bool canAssign)
|
||||||
{
|
{
|
||||||
if (digester.Class == null)
|
if (digester.ClassBuilder == null)
|
||||||
digester.ErrorAtPrevious("We're currently not in a class. 'this' only refers to the current instance of one.");
|
digester.ErrorAtPrevious("We're currently not in a class. 'this' only refers to the current instance of one.");
|
||||||
else
|
else
|
||||||
Variable(digester, false);
|
Variable(digester, false);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ public readonly record struct Instruction(byte Code)
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
if ((Code & 0x80) == 0x80)
|
||||||
|
return $"<Dynamic ({Code ^ 0x80})>";
|
||||||
return $"<{OpCode} ({Code})>";
|
return $"<{OpCode} ({Code})>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -20,7 +20,7 @@ public enum OpCode
|
||||||
GetProperty,
|
GetProperty,
|
||||||
SetProperty,
|
SetProperty,
|
||||||
Property,
|
Property,
|
||||||
GetSuper,
|
Base,
|
||||||
Equal,
|
Equal,
|
||||||
Greater,
|
Greater,
|
||||||
Less,
|
Less,
|
||||||
|
|
@ -53,7 +53,7 @@ public enum OpCode
|
||||||
Loop,
|
Loop,
|
||||||
Call,
|
Call,
|
||||||
Invoke,
|
Invoke,
|
||||||
SuperInvoke,
|
BaseCall,
|
||||||
Closure,
|
Closure,
|
||||||
CloseUpvalue,
|
CloseUpvalue,
|
||||||
Return,
|
Return,
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,18 @@ namespace Qrakhen.Qamp.Core.Execution;
|
||||||
|
|
||||||
using Op = OpCode;
|
using Op = OpCode;
|
||||||
|
|
||||||
public class GetPtr<T>
|
public class Pointer<T>
|
||||||
{
|
{
|
||||||
public IGetSet<long, T> Target;
|
public IGetSet<long, T> Target;
|
||||||
public long Pointer;
|
public long Ptr;
|
||||||
|
|
||||||
public GetPtr(IGetSet<long, T> target, long pointer = 0)
|
public Pointer(IGetSet<long, T> target, long pointer = 0)
|
||||||
{
|
{
|
||||||
Target = target;
|
Target = target;
|
||||||
Pointer = pointer;
|
Ptr = pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Next() => Target.Get(Pointer++);
|
public T Next() => Target.Get(Ptr++);
|
||||||
|
|
||||||
public void Set(long position, T value)
|
public void Set(long position, T value)
|
||||||
{
|
{
|
||||||
|
|
@ -35,7 +35,7 @@ public class GetPtr<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is all a bit cheesy imho
|
// this is all a bit cheesy imho
|
||||||
public class InstructionPtr : GetPtr<Instruction>
|
public class InstructionPtr : Pointer<Instruction>
|
||||||
{
|
{
|
||||||
public Segment Segment;
|
public Segment Segment;
|
||||||
|
|
||||||
|
|
@ -46,36 +46,49 @@ public class InstructionPtr : GetPtr<Instruction>
|
||||||
|
|
||||||
public long NextLong()
|
public long NextLong()
|
||||||
{
|
{
|
||||||
long value = Segment.ReadLong(Pointer);
|
long value = Segment.ReadLong(Ptr);
|
||||||
Pointer += sizeof(long);
|
Ptr += sizeof(long);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Value NextConstant()
|
public Value NextConstant()
|
||||||
{
|
{
|
||||||
return Segment.Constants[NextLong()];
|
return Segment.Constants[NextDynamic()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long NextDynamic()
|
||||||
|
{
|
||||||
|
int length = Segment.Read(Ptr) ^ 0x80;
|
||||||
|
Ptr++;
|
||||||
|
byte[] data = new byte[8];
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
data[i] = Segment.Read(Ptr++);
|
||||||
|
}
|
||||||
|
return data.ToInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public String? GetString(long offset)
|
public String? GetString(long offset)
|
||||||
{
|
{
|
||||||
return Segment.Constants[offset].Ptr.Value as String;
|
return Segment.Constants[offset].Ptr.Value as String;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instruction Instruction => Segment.Instructions[Pointer];
|
public Instruction Instruction => Segment.Instructions[Ptr];
|
||||||
|
|
||||||
public static Instruction operator +(InstructionPtr ptr, int value) => ptr.Segment.Instructions[ptr.Pointer + value];
|
public static Instruction operator +(InstructionPtr ptr, int value) => ptr.Segment.Instructions[ptr.Ptr + value];
|
||||||
|
|
||||||
public static Instruction operator -(InstructionPtr ptr, int value) => ptr.Segment.Instructions[ptr.Pointer - value];
|
public static Instruction operator -(InstructionPtr ptr, int value) => ptr.Segment.Instructions[ptr.Ptr - value];
|
||||||
|
|
||||||
public static InstructionPtr operator ++(InstructionPtr ptr)
|
public static InstructionPtr operator ++(InstructionPtr ptr)
|
||||||
{
|
{
|
||||||
ptr.Pointer++;
|
ptr.Ptr++;
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InstructionPtr operator --(InstructionPtr ptr)
|
public static InstructionPtr operator --(InstructionPtr ptr)
|
||||||
{
|
{
|
||||||
ptr.Pointer--;
|
ptr.Ptr--;
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -84,13 +97,13 @@ public class Call
|
||||||
{
|
{
|
||||||
public Closure Closure;
|
public Closure Closure;
|
||||||
public InstructionPtr Ptr;
|
public InstructionPtr Ptr;
|
||||||
public GetPtr<Value> StackPtr;
|
public Pointer<Value> StackPtr;
|
||||||
|
|
||||||
public Call(Closure closure, StackLike<Value> stack, long stackOffset)
|
public Call(Closure closure, StackLike<Value> stack, long stackOffset)
|
||||||
{
|
{
|
||||||
Closure = closure;
|
Closure = closure;
|
||||||
Ptr = new InstructionPtr(Closure.Function.Segment);
|
Ptr = new InstructionPtr(Closure.Function.Segment);
|
||||||
StackPtr = new GetPtr<Value>(stack, stackOffset);
|
StackPtr = new Pointer<Value>(stack, stackOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,21 +175,21 @@ public class Runner : IDisposable
|
||||||
case Op.BitwiseRight: OpBitwiseRight(); break;
|
case Op.BitwiseRight: OpBitwiseRight(); break;
|
||||||
|
|
||||||
case Op.GetLocal: {
|
case Op.GetLocal: {
|
||||||
long slot = call.Ptr.NextLong();
|
long slot = call.Ptr.NextDynamic();
|
||||||
_logger.Verbose($"getting slot {slot} which is {call.StackPtr.Get(slot)}");
|
_logger.Verbose($"getting slot {slot} which is {call.StackPtr.Get(slot)}");
|
||||||
Push(call.StackPtr.Get(slot));
|
Push(call.StackPtr.Get(slot));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Op.SetLocal: {
|
case Op.SetLocal: {
|
||||||
long slot = call.Ptr.NextLong();
|
long slot = call.Ptr.NextDynamic();
|
||||||
_logger.Verbose($"setting stackptr {slot} to {Peek()}");
|
_logger.Verbose($"setting stackptr {slot} to {Peek()}");
|
||||||
call.StackPtr.Set(slot, Peek());
|
call.StackPtr.Set(slot, Peek());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Op.DefineGlobal: {
|
case Op.DefineGlobal: {
|
||||||
string? name = call.Ptr.GetString(call.Ptr.NextLong())?.Value;
|
string? name = call.Ptr.GetString(call.Ptr.NextDynamic())?.Value;
|
||||||
if (string.IsNullOrEmpty(name))
|
if (string.IsNullOrEmpty(name))
|
||||||
throw new ExecutionException($"tried to define global variable with empty name");
|
throw new ExecutionException($"tried to define global variable with empty name");
|
||||||
Globals[name] = Pop();
|
Globals[name] = Pop();
|
||||||
|
|
@ -185,7 +198,7 @@ public class Runner : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
case Op.SetGlobal: {
|
case Op.SetGlobal: {
|
||||||
string? name = call.Ptr.GetString(call.Ptr.NextLong())?.Value;
|
string? name = call.Ptr.GetString(call.Ptr.NextDynamic())?.Value;
|
||||||
if (string.IsNullOrEmpty(name))
|
if (string.IsNullOrEmpty(name))
|
||||||
throw new ExecutionException($"tried to set global variable with empty name");
|
throw new ExecutionException($"tried to set global variable with empty name");
|
||||||
if (!Globals.Has(name))
|
if (!Globals.Has(name))
|
||||||
|
|
@ -229,13 +242,13 @@ public class Runner : IDisposable
|
||||||
Pop();
|
Pop();
|
||||||
return ExecutionResult.OK;
|
return ExecutionResult.OK;
|
||||||
}
|
}
|
||||||
Cursor = call.StackPtr.Pointer; // well find a better way...
|
Cursor = call.StackPtr.Ptr; // well find a better way...
|
||||||
Push(result);
|
Push(result);
|
||||||
call = Calls.Peek();
|
call = Calls.Peek();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (call.Ptr.Segment.Instructions.Length > call.Ptr.Pointer);
|
} while (call.Ptr.Segment.Instructions.Length > call.Ptr.Ptr);
|
||||||
|
|
||||||
return ExecutionResult.OK;
|
return ExecutionResult.OK;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ public class Segment(
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public long ReadDynamic(long offset, out byte length)
|
public long ReadDynamic(long offset, out byte length)
|
||||||
{
|
{
|
||||||
length = Read(offset, 1)[0];
|
length = (byte)(Read(offset) ^ 0x80);
|
||||||
byte[] bytes = new byte[8];
|
byte[] bytes = new byte[8];
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
bytes[i] = Instructions[offset + 1 + i];
|
bytes[i] = Instructions[offset + 1 + i];
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,27 @@ public static class Extensions
|
||||||
stream.SetLength(stream.Length - amount);
|
stream.SetLength(stream.Length - amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 byte[] GetBytes(this short 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 ushort value) => BitConverter.GetBytes(value);
|
||||||
public static byte[] GetBytes(this int value) => BitConverter.GetBytes(value);
|
public static byte[] GetBytes(this int value) => BitConverter.GetBytes(value);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue