add lists, itemprovider logic, structs
This commit is contained in:
parent
53fdea4d18
commit
367b334b79
|
|
@ -126,9 +126,9 @@ public static class ExpressionParser
|
|||
digester.Emit(OpCode.ArrayAdd);
|
||||
} else if (canAssign && digester.Match(TokenType.Equal)) {
|
||||
digester.ParseExpression();
|
||||
digester.Emit(OpCode.ArraySet);
|
||||
digester.Emit(OpCode.SetItem);
|
||||
} else {
|
||||
digester.Emit(OpCode.ArrayGet);
|
||||
digester.Emit(OpCode.GetItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,10 +56,12 @@ public enum OpCode
|
|||
Decrement = 0x71,
|
||||
|
||||
Array = 0xc0,
|
||||
ArrayGet = 0xc1,
|
||||
ArraySet = 0xc2,
|
||||
ArrayAdd = 0xc3,
|
||||
ArrayRemove = 0xc4,
|
||||
List = 0xc1,
|
||||
Structure = 0xc2,
|
||||
GetItem = 0xc3,
|
||||
SetItem = 0xc4,
|
||||
AddItem = 0xc5,
|
||||
RemoveItem = 0xc6,
|
||||
|
||||
Return = 0x80,
|
||||
Jump = 0x81,
|
||||
|
|
|
|||
|
|
@ -204,44 +204,48 @@ public class Runner : IDisposable
|
|||
break;
|
||||
}
|
||||
|
||||
case Op.ArrayGet: {
|
||||
case Op.GetItem: {
|
||||
Value index = Pop();
|
||||
Value array = Pop();
|
||||
if (!array.Is(T.Array))
|
||||
return Error($"Can not access {index} of {array} - it is not an array.");
|
||||
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 (index.IsSigned)
|
||||
Push(array.Ptr.As<Values.Objects.Array>()!.Get((int)index.Signed));
|
||||
else if (index.IsUnsigned)
|
||||
Push(array.Ptr.As<Values.Objects.Array>()!.Get((int)index.Unsigned));
|
||||
if (items.Is(T.Array))
|
||||
Push(items.Ptr.As<Values.Objects.Array>()!.Get(index));
|
||||
else if (items.Is(T.List))
|
||||
Push(items.Ptr.As<Values.Objects.List>()!.Get(index));
|
||||
else if (items.Is(T.Structure))
|
||||
Push(items.Ptr.As<Values.Objects.Structure>()!.Get(index));
|
||||
else
|
||||
return Error($"Can not access {index}, index is not an integer.");
|
||||
return Error($"Unsupported native accessor for type {items.Type}!");
|
||||
break;
|
||||
}
|
||||
|
||||
case Op.ArraySet: {
|
||||
case Op.SetItem: {
|
||||
Value value = Pop();
|
||||
Value index = Pop();
|
||||
Value array = Pop();
|
||||
if (!array.Is(T.Array))
|
||||
return Error($"Can not access {index} of {array} - it is not an array.");
|
||||
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 (index.IsSigned)
|
||||
array.Ptr.As<Values.Objects.Array>()!.Set((int)index.Signed, value);
|
||||
else if (index.IsUnsigned)
|
||||
array.Ptr.As<Values.Objects.Array>()!.Set((int)index.Signed, value);
|
||||
if (items.Is(T.Array))
|
||||
items.Ptr.As<Values.Objects.Array>()!.Set(index, value);
|
||||
else if (items.Is(T.List))
|
||||
items.Ptr.As<Values.Objects.List>()!.Set(index, value);
|
||||
else if (items.Is(T.Structure))
|
||||
items.Ptr.As<Values.Objects.Structure>()!.Set(index, value);
|
||||
else
|
||||
return Error($"Can not access {index}, index is not an integer.");
|
||||
return Error($"Unsupported native accessor for type {items.Type}!");
|
||||
break;
|
||||
}
|
||||
|
||||
case Op.ArrayAdd: {
|
||||
case Op.AddItem: {
|
||||
Value value = Pop();
|
||||
Value array = Pop();
|
||||
if (!array.Is(T.Array))
|
||||
return Error($"Can not add {value} to {array} - it is not an array.");
|
||||
Value items = Pop();
|
||||
if (!items.Is(T.List))
|
||||
return Error($"Can not add {value} to {items} - only lists :[] support the native add <+ operator.");
|
||||
|
||||
array.Ptr.As<Values.Objects.Array>()!.Add(value);
|
||||
items.Ptr.As<Values.Objects.List>()!.Add(value);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -279,7 +279,9 @@ public class Reader : IReader<Token>, IDisposable
|
|||
';' => MakeToken(Semicolon, buffer),
|
||||
':' => Check(':') ?
|
||||
MakeToken(Print, buffer + Next()) :
|
||||
MakeToken(Colon, buffer),
|
||||
Check('(') ?
|
||||
MakeToken(ListOpen, buffer + Next()) :
|
||||
MakeToken(Colon, buffer),
|
||||
'&' => Check('&') ?
|
||||
MakeToken(And, buffer + Next()) :
|
||||
MakeToken(BitwiseAnd, buffer),
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ public enum TokenType
|
|||
|
||||
ArrayOpen = Bracket | 5,
|
||||
ArrayClose = Bracket | 6,
|
||||
ListOpen = Bracket | 7,
|
||||
|
||||
ArrayAdd,
|
||||
ArrayRemove,
|
||||
|
|
|
|||
|
|
@ -1,32 +1,39 @@
|
|||
namespace Qrakhen.Qamp.Core.Values.Objects;
|
||||
using System;
|
||||
|
||||
public class Array(IEnumerable<Value> data) : Obj(ValueType.Array)
|
||||
namespace Qrakhen.Qamp.Core.Values.Objects;
|
||||
|
||||
public class Array(IEnumerable<Value> data) : ItemProvider<int>(ValueType.Array)
|
||||
{
|
||||
public List<Value> Data = [..data];
|
||||
|
||||
public void Set(int index, Value value)
|
||||
public Value[] Data = [..data];
|
||||
protected override void InnerSet(int index, Value value)
|
||||
{
|
||||
AssertWithinBounds(index);
|
||||
Data[index] = value;
|
||||
}
|
||||
|
||||
public Value Get(int index)
|
||||
protected override Value InnerGet(int index)
|
||||
{
|
||||
AssertWithinBounds(index);
|
||||
return Data[index];
|
||||
}
|
||||
|
||||
public void Add(Value value)
|
||||
protected override void AssertValidAccesor(int index)
|
||||
{
|
||||
Data.Add(value);
|
||||
if (index < 0 || index > Data.Length)
|
||||
throw new ItemProviderException($"Can not index '{index}' of array, as the index is outside its boundaries.", this);
|
||||
}
|
||||
|
||||
private void AssertWithinBounds(int index)
|
||||
protected override int ExtractIndex(Value value)
|
||||
{
|
||||
if (index < 0 || index > Data.Count)
|
||||
throw new QampException($"Can not access element at index {index}, it is outside of this array's bounds.");
|
||||
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;
|
||||
}
|
||||
|
||||
public override string ToString() => ToString(true);
|
||||
public string ToString(bool detail) => detail ? $"[{string.Join(", ", Data)}]" : $"Array[{Data.Count}]";
|
||||
public string ToString(bool detail) => detail ? $"[{string.Join(", ", Data)}]" : $"Array[{Data.Length}]";
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
namespace Qrakhen.Qamp.Core.Values.Objects;
|
||||
|
||||
public class Dictionary(IEnumerable<KeyValuePair<string, Value>> data) : Obj(ValueType.Object)
|
||||
{
|
||||
public Dictionary<string, Value> Data = new(data);
|
||||
|
||||
public void Set(string key, Value value)
|
||||
{
|
||||
Data[key] = value;
|
||||
}
|
||||
|
||||
public Value Get(string key)
|
||||
{
|
||||
if (Data.TryGetValue(key, out Value value))
|
||||
return value;
|
||||
return Value.Void;
|
||||
}
|
||||
|
||||
public override string ToString() => $"[{string.Join(", ", Data)}]";
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
namespace Qrakhen.Qamp.Core.Values.Objects;
|
||||
|
||||
public abstract class ItemProvider<T>(ValueType type) : Obj(type)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public class ItemProviderException(string message, object context) : QampException(message, context);
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
namespace Qrakhen.Qamp.Core.Values.Objects;
|
||||
|
||||
public class List(IEnumerable<Value> data) : ItemProvider<int>(ValueType.List)
|
||||
{
|
||||
public List<Value> Data = [..data];
|
||||
|
||||
public void Add(Value value)
|
||||
{
|
||||
Data.Add(value);
|
||||
}
|
||||
|
||||
public void Remove(Value index)
|
||||
{
|
||||
int _index = ExtractIndex(index);
|
||||
AssertValidAccesor(_index);
|
||||
Data.RemoveAt(_index);
|
||||
}
|
||||
|
||||
protected override void InnerSet(int index, Value value)
|
||||
{
|
||||
Data[index] = value;
|
||||
}
|
||||
|
||||
protected override Value InnerGet(int index)
|
||||
{
|
||||
return Data[index];
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
public override string ToString() => ToString(true);
|
||||
public string ToString(bool detail) => detail ? $":[{string.Join(", ", Data)}]" : $"List[{Data.Count}]";
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
namespace Qrakhen.Qamp.Core.Values.Objects;
|
||||
|
||||
public class Structure(IEnumerable<KeyValuePair<string, Value>> data) : ItemProvider<string>(ValueType.Structure)
|
||||
{
|
||||
public bool Sealed;
|
||||
public Dictionary<string, Value> Data = new(data);
|
||||
|
||||
protected override void InnerSet(string index, Value value)
|
||||
{
|
||||
Data[index] = value;
|
||||
}
|
||||
|
||||
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 string ExtractIndex(Value value)
|
||||
{
|
||||
string index;
|
||||
if (value.IsString)
|
||||
index = value.Ptr.As<String>()!.Value!;
|
||||
else
|
||||
throw new ItemProviderException($"Can not use {value} as an accessor, as it is not a string.", this);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public override string ToString() => ToString(true);
|
||||
public string ToString(bool detail) => detail ? $"{{{string.Join("\n,", Data)}}}" : $"Structure{{{Data.Count}}}";
|
||||
}
|
||||
|
|
@ -23,18 +23,23 @@ public enum ValueType
|
|||
|
||||
// classes etc. here?
|
||||
|
||||
Reference = 0x1000,
|
||||
Pointer = 0x2000,
|
||||
Object = Pointer, // coded with & symbol
|
||||
Native = Object | 0x0001,
|
||||
String = Object | 0x0002,
|
||||
Array = Object | 0x0004,
|
||||
Function = Object | 0x0008,
|
||||
Context = Object | 0x0010,
|
||||
Instance = Object | 0x0020,
|
||||
Class = Object | 0x0100,
|
||||
Method = Class | Function,
|
||||
Outer = Object | 0x0200,
|
||||
Reference = 0x1000,
|
||||
Pointer = 0x2000,
|
||||
|
||||
Module = 0xFFFF
|
||||
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,
|
||||
|
||||
Module = 0xFFFF
|
||||
}
|
||||
Loading…
Reference in New Issue