using System.Numerics;
using System.Runtime.CompilerServices;

namespace NTDLS.ExpressionParser
{
    internal static class Extensions
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static int ToCacheIndex(this string key) => int.Parse(key[1..^1]);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static bool IsNativeFunction(this string value) => Constants.NativeFunctions.Contains(value);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static bool IsIntegerExclusiveOperation(this string value) => (new string[] { "&", "|", "^", "&=", "|=", "^=", "<<", ">>" }).Contains(value);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static bool IsMathCharacter(this char value) => (new char[] { '*', '/', '+', '-', '>', '<', '!', '=', '&', '|', '^', '%', '~' }).Contains(value);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static bool IsValidVariableCharacter(this char value) => char.IsDigit(value) || (value >= 'a' && value <= 'z') || (value >= 'A' && value <= 'Z') || value == '_';

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static bool IsNumeric(this string input)
        {
            if (string.IsNullOrEmpty(input))
                return false;

            bool hasDigit = false;

            int i = 0;

            if (input[i] == '-' || input[i] == '+') //Explicit positive or negative number.
            {
                i++;
            }

            for (; i < input.Length; i++)
            {
                char c = input[i];

                if (char.IsDigit(c))
                {
                    hasDigit = true;
                    continue;
                }

                if ((c == '.' || c == ',') || (c == '-' || c == '+' && i == 0))
                    continue;

                return false;
            }

            return hasDigit;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static int ComputeIntegerExclusivePrimitive(this string operation, int leftValue, int rightValue)
        {
            return operation switch
            {
                "!" => (leftValue != rightValue) ? 1 : 0,
                "&" => leftValue & rightValue,
                "&&" => (leftValue != 0 && rightValue != 0) ? 1 : 0,
                "&=" => leftValue &= rightValue,
                "^" => leftValue ^ rightValue,
                "^=" => leftValue ^= rightValue,
                "|" => leftValue | rightValue,
                "||" => (leftValue != 0 || rightValue != 0) ? 1 : 0,
                "|=" => leftValue |= rightValue,
                "~" => ~leftValue,
                "<<" => leftValue << rightValue,
                "=" => (leftValue == rightValue) ? 1 : 0,
                ">>" => leftValue >> rightValue,
                _ => throw new Exception($"Invalid operator: {operation}"),
            };
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static double ComputePrivative(this string operation, double leftValue, double rightValue)
        {
            if (operation.IsIntegerExclusiveOperation())
            {
                return operation.ComputeIntegerExclusivePrimitive((int)leftValue, (int)rightValue);
            }

            var result = operation switch
            {
                "!" => (leftValue != rightValue) ? 1 : 0,
                "!=" => (leftValue != rightValue) ? 1 : 0,
                "-" => (leftValue - rightValue),
                "%" => rightValue != 0 ? (leftValue % rightValue) : throw new Exception("Divide by zero (mod)."),
                "&&" => (leftValue != 0 && rightValue != 0) ? 1 : 0,
                "*" => (leftValue * rightValue),
                "/" => rightValue != 0 ? (leftValue / rightValue) : throw new Exception("Divide by zero."),
                "||" => (leftValue != 0 || rightValue != 0) ? 1 : 0,
                "+" => (leftValue + rightValue),
                "<" => (leftValue < rightValue) ? 1 : 0,
                "<=" => (leftValue <= rightValue) ? 1 : 0,
                "<>" => (leftValue != rightValue) ? 1 : 0,
                "=" => (leftValue == rightValue) ? 1 : 0,
                ">" => (leftValue > rightValue) ? 1 : 0,
                ">=" => (leftValue >= rightValue) ? 1 : 0,
                _ => throw new Exception($"Invalid operator: {operation}"),
            };

            if (double.IsNaN(result))
            {
                throw new Exception($"Result of {operation} is NaN.");
            }

            if (double.IsInfinity(result))
            {
                throw new Exception($"Result of {operation} is infinite.");
            }

            return result;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static double ComputeNativeFunction(this string functionName, double[] parameters)
        {
            return functionName switch
            {
                "abs" => parameters.Length == 1 ? (Math.Abs(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "acos" => parameters.Length == 1 ? (Math.Acos(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "asin" => parameters.Length == 1 ? (Math.Asin(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "atan" => parameters.Length == 1 ? (Math.Atan(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "atan2" => parameters.Length == 2 ? (Math.Atan2(parameters[0], parameters[1])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "avg" => parameters.Length > 0 ? (parameters.Average()) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "ceil" => parameters.Length == 1 ? (Math.Ceiling(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "cos" => parameters.Length == 1 ? (Math.Cos(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "cosh" => parameters.Length == 1 ? (Math.Cosh(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "exp" => parameters.Length == 1 ? (Math.Exp(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "floor" => parameters.Length == 1 ? (Math.Floor(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "log" => parameters.Length == 1 ? (Math.Log(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "log10" => parameters.Length == 1 ? (Math.Log10(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "max" => parameters.Length > 0 ? (parameters.Max()) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "min" => parameters.Length > 0 ? (parameters.Min()) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "modpow" => parameters.Length == 3 ? ((double)BigInteger.ModPow((BigInteger)parameters[0], (BigInteger)parameters[1], (BigInteger)parameters[2])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "not" => parameters.Length == 1 ? ((parameters[0] == 0) ? 1 : 0) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "pow" => parameters.Length == 2 ? (Math.Pow(parameters[0], (int)parameters[1])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "sin" => parameters.Length == 1 ? (Math.Sin(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "sinh" => parameters.Length == 1 ? (Math.Sinh(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "sqrt" => parameters.Length == 1 ? (Math.Sqrt(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "sum" => parameters.Length > 0 ? (parameters.Sum()) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "tahn" => parameters.Length == 1 ? (Math.Tanh(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                "tan" => parameters.Length == 1 ? (Math.Tan(parameters[0])) : throw new Exception($"Invalid number of parameters passed to function: {functionName}"),
                _ => throw new Exception($"Undefined native function: {functionName}"),
            };
        }
    }
}


Last modified by Admin @ 10/22/2025 3:55:40 PM

Comments

Login to leave a comment.
View all comments