using Qrakhen.Qamp.Core.Collections; using Qrakhen.Qamp.Core.Logging; using Qrakhen.Qamp.Core.Values; namespace Qrakhen.Qamp.Core.Execution; public readonly record struct Operation(OpCode OpCode, Value Left, Value Right); public delegate Value OperationHandler(Operation operation); public static class ValueOperation { private static readonly ILogger _logger = LoggerService.Get(nameof(ValueOperation)); private static readonly Register _operations; public static Value Resolve(Operation operation) { #if LOG _logger.Method($"{operation.Left} {operation.OpCode} {operation.Right}"); #endif // p sure switch is faster here (as opposed to dict lookup) return operation.OpCode switch { OpCode.Equal => Equal(operation), OpCode.Greater => Greater(operation), OpCode.Less => Less(operation), OpCode.Not => Not(operation), OpCode.Add => Add(operation), OpCode.Subtract => Subtract(operation), OpCode.Divide => Divide(operation), OpCode.Modulo => Modulo(operation), OpCode.Multiply => Multiply(operation), OpCode.Negate => Negate(operation), OpCode.BitwiseOr => BitwiseOr(operation), OpCode.BitwiseAnd => BitwiseAnd(operation), OpCode.BitwiseLeft => BitwiseLeft(operation), OpCode.BitwiseRight => BitwiseRight(operation), OpCode.BitwiseNot => BitwiseInvert(operation), OpCode.BitwiseXor => BitwiseXor(operation), _ => throw new NotImplementedException($"Unknown operator {operation.OpCode}.") }; } static ValueOperation() { _operations = new Register { { OpCode.Equal, Equal }, { OpCode.Greater, Greater }, { OpCode.Less, Less }, { OpCode.Not, Not }, { OpCode.Add, Add }, { OpCode.Subtract, Subtract }, { OpCode.Divide, Divide }, { OpCode.Modulo, Modulo }, { OpCode.Multiply, Multiply }, { OpCode.Negate, Negate }, { OpCode.BitwiseOr, BitwiseOr }, { OpCode.BitwiseAnd, BitwiseAnd }, { OpCode.BitwiseLeft, BitwiseLeft }, { OpCode.BitwiseRight, BitwiseRight }, { OpCode.BitwiseNot, BitwiseInvert }, { OpCode.BitwiseXor, BitwiseXor } }; } public static Value Equal(Operation operation) { Value a = operation.Left; Value b = operation.Right; Assert.NotVoid(a, b); Assert.IsPrimitive(a, b); return new Value(a.Dynamic == b.Dynamic); } public static Value Greater(Operation operation) { Value a = operation.Left; Value b = operation.Right; Assert.NotVoid(a, b); Assert.IsPrimitive(a, b); return new Value(a.Dynamic > b.Dynamic); } public static Value Less(Operation operation) { Value a = operation.Left; Value b = operation.Right; Assert.NotVoid(a, b); Assert.IsPrimitive(a, b); return new Value(a.Dynamic < b.Dynamic); } public static Value Not(Operation operation) { Value value = operation.Left; Assert.NotVoid(value); ulong inner = value.Unsigned; return new Value(inner == 0); } public static Value Add(Operation operation) { Value a = operation.Left; Value b = operation.Right; Assert.NotVoid(a, b); if (a.IsString) return Values.Objects.String.Make($"{a}{b}"); Assert.IsPrimitive(a, b); bool convert = a.Type != b.Type; return new Value(a.Dynamic + b.Dynamic); } public static Value Subtract(Operation operation) { Value a = operation.Left; Value b = operation.Right; Assert.NotVoid(a, b); Assert.IsPrimitive(a, b); return new Value(a.Dynamic - b.Dynamic); } public static Value Divide(Operation operation) { Value a = operation.Left; Value b = operation.Right; Assert.NotVoid(a, b); Assert.IsPrimitive(a, b); Assert.NotZero(b); return new Value(a.Dynamic / b.Dynamic); } public static Value Modulo(Operation operation) { Value a = operation.Left; Value b = operation.Right; Assert.NotVoid(a, b); Assert.IsPrimitive(a, b); Assert.NotZero(b); return new Value(a.Dynamic % b.Dynamic); } public static Value Multiply(Operation operation) { Value a = operation.Left; Value b = operation.Right; Assert.NotVoid(a, b); Assert.IsPrimitive(a, b); return new Value(a.Dynamic * b.Dynamic); } public static Value Negate(Operation operation) { Value value = operation.Left; Assert.NotVoid(value); Assert.IsPrimitive(value); return new Value(-value.Dynamic); } public static Value BitwiseOr(Operation operation) { Value a = operation.Left; Value b = operation.Right; Assert.NotVoid(a, b); Assert.IsPrimitive(a, b); Assert.IsInteger(a, b); return new Value(a.Dynamic | b.Dynamic); } public static Value BitwiseAnd(Operation operation) { Value a = operation.Left; Value b = operation.Right; Assert.NotVoid(a, b); Assert.IsPrimitive(a, b); Assert.IsInteger(a, b); return new Value(a.Dynamic & b.Dynamic); } public static Value BitwiseXor(Operation operation) { Value a = operation.Left; Value b = operation.Right; Assert.NotVoid(a, b); Assert.IsPrimitive(a, b); Assert.IsInteger(a, b); return new Value(a.Dynamic ^ b.Dynamic); } public static Value BitwiseLeft(Operation operation) { Value a = operation.Left; Value b = operation.Right; Assert.NotVoid(a, b); Assert.IsPrimitive(a, b); Assert.IsInteger(a, b); return new Value(a.Dynamic << (int)(b.Dynamic ?? 0)); } public static Value BitwiseRight(Operation operation) { Value a = operation.Left; Value b = operation.Right; Assert.NotVoid(a, b); Assert.IsPrimitive(a, b); Assert.IsInteger(a, b); return new Value(a.Dynamic >> (int)(b.Dynamic ?? 0)); } public static Value BitwiseInvert(Operation operation) { Value a = operation.Left; Assert.NotVoid(a); Assert.IsPrimitive(a); Assert.IsInteger(a); return new Value(~a.Dynamic); } }