diff --git a/Qrakhen.Qamp.CLI/Program.cs b/Qrakhen.Qamp.CLI/Program.cs index f799d96..3768fbd 100644 --- a/Qrakhen.Qamp.CLI/Program.cs +++ b/Qrakhen.Qamp.CLI/Program.cs @@ -34,116 +34,9 @@ void Init(string[] args) } Init(args); - -void git(string path, string cmd) -{ - Console.WriteLine($" > git {cmd}"); - ProcessStartInfo info = new ProcessStartInfo{ - WorkingDirectory = path, - FileName = "git", - Arguments = cmd - }; - Process.Start(info)?.WaitForExit(); -} - -void del(string path, string cmd) -{ - Console.WriteLine($" > git {cmd}"); - ProcessStartInfo info = new ProcessStartInfo{ - WorkingDirectory = path, - FileName = "del", - Arguments = $"{cmd} /F /Q /S" - }; - Process.Start(info)?.WaitForExit(); -} - -string x = @"C:\Users\filos\projects"; -string[] check = ["node_modules", "bin", "obj", "Library"]; -int scanx(string path) -{ - foreach (var dir in Directory.EnumerateDirectories(path)) { - try { - var name = dir.Replace(path, "").Replace(@"\", ""); - if (!check.Contains(name)) { - scanx(dir); - } else { - Console.WriteLine(dir + " (" + (Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length) + " files)"); - if ((Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length) == 0) { - Console.WriteLine(" skipped (0 files)"); - continue; - } - if (name == "Library") { - if (!Directory.Exists(path + "\\Assets")) { - Console.WriteLine(" skipped (not a definite unity library folder)"); - continue; - } - } - Console.Write(name == "Library" ? " y/n?" : ""); - do { - char c = name == "Library" ? Console.ReadKey(true).KeyChar : 'y'; - if (c == 'y') { - Directory.Delete(dir, true); - break; - } else if (c == 'n') { - break; - } else { - Console.WriteLine(string.Join("\n", Directory.EnumerateDirectories(dir).Select(_ => $" + {_}"))); - Console.WriteLine(string.Join("\n", Directory.EnumerateFiles(dir).Select(_ => $" - {_}"))); - } - } while (true); - } - } catch(Exception e) { Console.WriteLine("ERROR: " + e.Message); } - } - return 0; -} - -scanx(x); -return; - - -string path = @"C:\Users\filos\projects"; -string[] ignore = ["node_modules", "bin", "obj", "Debug", "Build", ".vs"]; -int scan(string path) -{ - foreach (var dir in Directory.EnumerateDirectories(path)) { - var name = dir.Replace(path, "").Replace(@"\", ""); - if (ignore.Contains(name)) - continue; - if (name == ".git") { - Console.WriteLine(path); - git(path, "status"); - Console.Write("y/n? "); - do { - char c = (char)Console.Read(); - if (c == 'y') { - Console.Write(" origin [master]? "); - string t = Console.ReadLine() ?? "master"; - if (string.IsNullOrEmpty(t)) - t = "master"; - - git(path, "add ."); - git(path, "commit -m \"backup commit\""); - git(path, "push origin " + t); - break; - } else if (c == 'n') { - break; - } else if (c > '0' && c < '9') { - return (48 - c); - } - } while (true); - } else { - int e = scan(dir); - if (e < 0) - return e+1; - } - } - return 0; -} - -scan(path); -return; */ + List Ignored = [ '\0', '\b' ]; LoggerService.Default = LogLevel.Error; List History = []; diff --git a/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs b/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs index 8d05e65..4f991ad 100644 --- a/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs +++ b/Qrakhen.Qamp.Core/Compilation/ExpressionParser.cs @@ -111,7 +111,13 @@ public static class ExpressionParser digester.EmitDynamic(OpCode.Array, length); // digester.MakeConstant(new Value((long)length))); } - static void ArrayAccessor(Digester digester, bool canAssign) + static void ArrayAdd(Digester digester, bool canAssign) + { + digester.ParseExpression(); + digester.Emit(OpCode.ArrayAdd); + } + + static void Accessor(Digester digester, bool canAssign) { digester.ParseExpression(); digester.Consume(TokenType.ArrayClose, "expected ] after array accessor"); @@ -242,63 +248,63 @@ public static class ExpressionParser static ExpressionParser() { - _rules[TokenType.GroupOpen] = new Rule(Group, Call, Weight.Call); - _rules[TokenType.GroupClose] = new Rule(null, null, Weight.None); - _rules[TokenType.ContextOpen] = new Rule(null, null, Weight.None); - _rules[TokenType.ContextClose] = new Rule(null, null, Weight.None); - _rules[TokenType.ArrayOpen] = new Rule(Array, ArrayAccessor, Weight.Call); - _rules[TokenType.ArrayClose] = new Rule(null, null, Weight.None); - _rules[TokenType.ArrayAdd] = new Rule(null, null, Weight.None); - _rules[TokenType.ArrayRemove] = new Rule(null, null, Weight.None); - _rules[TokenType.Colon] = new Rule(null, Dot, Weight.Call); - _rules[TokenType.Comma] = new Rule(null, null, Weight.None); - _rules[TokenType.Dot] = new Rule(null, Dot, Weight.Call); - _rules[TokenType.Minus] = new Rule(Modifier, Binary, Weight.Term); - _rules[TokenType.Plus] = new Rule(null, Binary, Weight.Term); - _rules[TokenType.Increment] = new Rule(Binary, Binary, Weight.Call); - _rules[TokenType.Decrement] = new Rule(Binary, Binary, Weight.Call); - _rules[TokenType.BitwiseAnd] = new Rule(Modifier, Binary, Weight.Term); - _rules[TokenType.BitwiseOr] = new Rule(null, Binary, Weight.Term); - _rules[TokenType.BitwiseXor] = new Rule(null, Binary, Weight.Term); - _rules[TokenType.BitwiseLeft] = new Rule(null, Binary, Weight.Term); - _rules[TokenType.BitwiseRight] = new Rule(null, Binary, Weight.Term); - _rules[TokenType.BitwiseNot] = new Rule(Modifier, null, Weight.Term); - _rules[TokenType.Semicolon] = new Rule(null, null, Weight.None); - _rules[TokenType.Slash] = new Rule(null, Binary, Weight.Factor); - _rules[TokenType.Star] = new Rule(null, Binary, Weight.Factor); - _rules[TokenType.Bang] = new Rule(Modifier, null, Weight.None); - _rules[TokenType.BangEqual] = new Rule(null, Binary, Weight.Equal); - _rules[TokenType.Equal] = new Rule(null, null, Weight.None); - _rules[TokenType.EqualEqual] = new Rule(null, Binary, Weight.Equal); - _rules[TokenType.Greater] = new Rule(null, Binary, Weight.Compare); - _rules[TokenType.GreaterEqual] = new Rule(null, Binary, Weight.Compare); - _rules[TokenType.Less] = new Rule(null, Binary, Weight.Compare); - _rules[TokenType.LessEqual] = new Rule(null, Binary, Weight.Compare); - _rules[TokenType.Identifier] = new Rule(Variable, null, Weight.None); - _rules[TokenType.String] = new Rule(String, null, Weight.None); - _rules[TokenType.Integer] = new Rule(Number, null, Weight.None); - _rules[TokenType.Hexadecimal] = new Rule(Number, null, Weight.None); - _rules[TokenType.Decimal] = new Rule(Number, null, Weight.None); - _rules[TokenType.And] = new Rule(null, And, Weight.And); - _rules[TokenType.Class] = new Rule(null, null, Weight.None); - _rules[TokenType.Else] = new Rule(null, null, Weight.None); - _rules[TokenType.False] = new Rule(Literal, null, Weight.None); - _rules[TokenType.For] = new Rule(null, null, Weight.None); - _rules[TokenType.Function] = new Rule(null, null, Weight.None); - _rules[TokenType.If] = new Rule(null, null, Weight.None); - _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(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.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); - _rules[TokenType.While] = new Rule(null, null, Weight.None); - _rules[TokenType.Error] = new Rule(null, null, Weight.None); - _rules[TokenType.Eof] = new Rule(null, null, Weight.None); + _rules[TokenType.GroupOpen] = new Rule(Group, Call, Weight.Call); + _rules[TokenType.GroupClose] = new Rule(null, null, Weight.None); + _rules[TokenType.ContextOpen] = new Rule(null, null, Weight.None); + _rules[TokenType.ContextClose] = new Rule(null, null, Weight.None); + _rules[TokenType.ArrayOpen] = new Rule(Array, Accessor, Weight.Call); + _rules[TokenType.ArrayClose] = new Rule(null, null, Weight.None); + _rules[TokenType.ArrayAdd] = new Rule(null, ArrayAdd, Weight.None); + _rules[TokenType.ArrayRemove] = new Rule(null, null, Weight.None); + _rules[TokenType.Colon] = new Rule(null, Dot, Weight.Call); + _rules[TokenType.Comma] = new Rule(null, null, Weight.None); + _rules[TokenType.Dot] = new Rule(null, Dot, Weight.Call); + _rules[TokenType.Minus] = new Rule(Modifier, Binary, Weight.Term); + _rules[TokenType.Plus] = new Rule(null, Binary, Weight.Term); + _rules[TokenType.Increment] = new Rule(Binary, Binary, Weight.Call); + _rules[TokenType.Decrement] = new Rule(Binary, Binary, Weight.Call); + _rules[TokenType.BitwiseAnd] = new Rule(Modifier, Binary, Weight.Term); + _rules[TokenType.BitwiseOr] = new Rule(null, Binary, Weight.Term); + _rules[TokenType.BitwiseXor] = new Rule(null, Binary, Weight.Term); + _rules[TokenType.BitwiseLeft] = new Rule(null, Binary, Weight.Term); + _rules[TokenType.BitwiseRight] = new Rule(null, Binary, Weight.Term); + _rules[TokenType.BitwiseNot] = new Rule(Modifier, null, Weight.Term); + _rules[TokenType.Semicolon] = new Rule(null, null, Weight.None); + _rules[TokenType.Slash] = new Rule(null, Binary, Weight.Factor); + _rules[TokenType.Star] = new Rule(null, Binary, Weight.Factor); + _rules[TokenType.Bang] = new Rule(Modifier, null, Weight.None); + _rules[TokenType.BangEqual] = new Rule(null, Binary, Weight.Equal); + _rules[TokenType.Equal] = new Rule(null, null, Weight.None); + _rules[TokenType.EqualEqual] = new Rule(null, Binary, Weight.Equal); + _rules[TokenType.Greater] = new Rule(null, Binary, Weight.Compare); + _rules[TokenType.GreaterEqual] = new Rule(null, Binary, Weight.Compare); + _rules[TokenType.Less] = new Rule(null, Binary, Weight.Compare); + _rules[TokenType.LessEqual] = new Rule(null, Binary, Weight.Compare); + _rules[TokenType.Identifier] = new Rule(Variable, null, Weight.None); + _rules[TokenType.String] = new Rule(String, null, Weight.None); + _rules[TokenType.Integer] = new Rule(Number, null, Weight.None); + _rules[TokenType.Hexadecimal] = new Rule(Number, null, Weight.None); + _rules[TokenType.Decimal] = new Rule(Number, null, Weight.None); + _rules[TokenType.And] = new Rule(null, And, Weight.And); + _rules[TokenType.Class] = new Rule(null, null, Weight.None); + _rules[TokenType.Else] = new Rule(null, null, Weight.None); + _rules[TokenType.False] = new Rule(Literal, null, Weight.None); + _rules[TokenType.For] = new Rule(null, null, Weight.None); + _rules[TokenType.Function] = new Rule(null, null, Weight.None); + _rules[TokenType.If] = new Rule(null, null, Weight.None); + _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(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.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); + _rules[TokenType.While] = new Rule(null, null, Weight.None); + _rules[TokenType.Error] = new Rule(null, null, Weight.None); + _rules[TokenType.Eof] = new Rule(null, null, Weight.None); } } diff --git a/Qrakhen.Qamp.Core/Execution/Runner.cs b/Qrakhen.Qamp.Core/Execution/Runner.cs index 7492aa5..2c1cbd5 100644 --- a/Qrakhen.Qamp.Core/Execution/Runner.cs +++ b/Qrakhen.Qamp.Core/Execution/Runner.cs @@ -205,17 +205,43 @@ public class Runner : IDisposable } case Op.ArrayGet: { - // attempt to retrieve nth element of array on stack + Value index = Pop(); + Value array = Pop(); + if (!array.Is(T.Array)) + return Error($"Can not access {index} of {array} - it is not an array."); + + if (index.IsSigned) + Push(array.Ptr.As()!.Get((int)index.Signed)); + else if (index.IsUnsigned) + Push(array.Ptr.As()!.Get((int)index.Unsigned)); + else + return Error($"Can not access {index}, index is not an integer."); break; } case Op.ArraySet: { - // set nth item on array + 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."); + + if (index.IsSigned) + array.Ptr.As()!.Set((int)index.Signed, value); + else if (index.IsUnsigned) + array.Ptr.As()!.Set((int)index.Signed, value); + else + return Error($"Can not access {index}, index is not an integer."); break; } case Op.ArrayAdd: { - // add to array + Value value = Pop(); + Value array = Pop(); + if (!array.Is(T.Array)) + return Error($"Can not add {value} to {array} - it is not an array."); + + array.Ptr.As()!.Add(value); break; } diff --git a/Qrakhen.Qamp.Core/Tokenization/Reader.cs b/Qrakhen.Qamp.Core/Tokenization/Reader.cs index c14b0a8..aa83965 100644 --- a/Qrakhen.Qamp.Core/Tokenization/Reader.cs +++ b/Qrakhen.Qamp.Core/Tokenization/Reader.cs @@ -318,13 +318,15 @@ public class Reader : IReader, IDisposable MakeToken(Equal, buffer), '<' => Check('~') ? MakeToken(Equal, buffer + Next()) : - Check(':') ? + Check(':') ? MakeToken(Return, buffer + Next()) : - Check('<') ? - MakeToken(BitwiseLeft, buffer + Next()) : - Check('=') ? - MakeToken(LessEqual, buffer + Next()) : - MakeToken(Less, buffer), + Check('+') ? + MakeToken(ArrayAdd, buffer + Next()) : + Check('<') ? + MakeToken(BitwiseLeft, buffer + Next()) : + Check('=') ? + MakeToken(LessEqual, buffer + Next()) : + MakeToken(Less, buffer), '>' => Check('>') ? MakeToken(BitwiseRight, buffer + Next()) : Check('=') ? diff --git a/Qrakhen.Qamp.Core/Values/Objects/Array.cs b/Qrakhen.Qamp.Core/Values/Objects/Array.cs index c0d61b4..945b918 100644 --- a/Qrakhen.Qamp.Core/Values/Objects/Array.cs +++ b/Qrakhen.Qamp.Core/Values/Objects/Array.cs @@ -6,11 +6,13 @@ public class Array(IEnumerable data) : Obj(ValueType.Array) public void Set(int index, Value value) { + AssertWithinBounds(index); Data[index] = value; } public Value Get(int index) { + AssertWithinBounds(index); return Data[index]; } @@ -19,5 +21,12 @@ public class Array(IEnumerable data) : Obj(ValueType.Array) Data.Add(value); } - public override string ToString() => $"[{string.Join(", ", Data)}]"; + private void AssertWithinBounds(int index) + { + if (index < 0 || index > Data.Count) + throw new QampException($"Can not access element at index {index}, it is outside of this array's bounds."); + } + + public override string ToString() => ToString(true); + public string ToString(bool detail) => detail ? $"[{string.Join(", ", Data)}]" : $"Array[{Data.Count}]"; } \ No newline at end of file