private void CheckCase(FunctionExpression function, string reference)
        {
            var called = function.Identifier.Name;

            if (IgnoreCase)
            {
                if (string.Equals(called, reference, StringComparison.InvariantCultureIgnoreCase))
                {
                    return;
                }

                throw new ArgumentException("Function not found.", called);
            }

            if (called != reference)
            {
                throw new ArgumentException($"Function not found: '{called}'. Try '{reference}' instead.");
            }
        }
        public override void Visit(FunctionExpression function)
        {
            var args = new FunctionArgs
            {
                Parameters = new Expression[function.Expressions.Length]
            };

            // Don't call parameters right now, instead let the function do it as needed.
            // Some parameters shouldn't be called, for instance, in a if(), the "not" value might be a division by zero
            // Evaluating every value could produce unexpected behaviour
            for (var i = 0; i < function.Expressions.Length; i++)
            {
                args.Parameters[i] = new Expression(function.Expressions[i], options);
                args.Parameters[i].EvaluateFunction  += EvaluateFunction;
                args.Parameters[i].EvaluateParameter += EvaluateParameter;

                // Assign the parameters of the Expression to the arguments so that custom Functions and Parameters can use them
                args.Parameters[i].Parameters = Parameters;
            }

            // Calls external implementation
            OnEvaluateFunction(IgnoreCase ? function.Identifier.Name.ToLower() : function.Identifier.Name, args);

            // If an external implementation was found get the result back
            if (args.HasResult)
            {
                Result = args.Result;
                return;
            }

            switch (function.Identifier.Name.ToLower(CultureInfo.InvariantCulture))
            {
            case "abs":
                CheckCase(function, "Abs");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Abs(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "acos":
                CheckCase(function, "Acos");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Acos(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "asin":
                CheckCase(function, "Asin");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Asin(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "atan":
                CheckCase(function, "Atan");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Atan(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "ceil":
                CheckCase(function, "Ceil");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Ceil(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "cos":
                CheckCase(function, "Cos");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Cos(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "exp":
                CheckCase(function, "Exp");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Exp(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "floor":
                CheckCase(function, "Floor");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Floor(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "log":
                CheckCase(function, "Log");
                CheckExactArgumentCount(function, 2);
                Result = Mathf.Log(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])), ConversionUtility.Convert <float>(Evaluate(function.Expressions[1])));
                break;

            case "log10":
                CheckCase(function, "Log10");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Log10(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "pow":
                CheckCase(function, "Pow");
                CheckExactArgumentCount(function, 2);
                Result = Mathf.Pow(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])), ConversionUtility.Convert <float>(Evaluate(function.Expressions[1])));
                break;

            case "round":
                CheckCase(function, "Round");
                CheckExactArgumentCount(function, 1);
                //var rounding = (options & EvaluateOptions.RoundAwayFromZero) == EvaluateOptions.RoundAwayFromZero ? MidpointRounding.AwayFromZero : MidpointRounding.ToEven;
                Result = Mathf.Round(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "sign":
                CheckCase(function, "Sign");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Sign(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));

                break;

            case "sin":
                CheckCase(function, "Sin");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Sin(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));
                break;

            case "sqrt":
                CheckCase(function, "Sqrt");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Sqrt(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));

                break;

            case "tan":
                CheckCase(function, "Tan");
                CheckExactArgumentCount(function, 1);
                Result = Mathf.Tan(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])));

                break;

            case "max":
                CheckCase(function, "Max");
                CheckExactArgumentCount(function, 2);
                Result = Mathf.Max(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])), ConversionUtility.Convert <float>(Evaluate(function.Expressions[1])));
                break;

            case "min":
                CheckCase(function, "Min");
                CheckExactArgumentCount(function, 2);
                Result = Mathf.Min(ConversionUtility.Convert <float>(Evaluate(function.Expressions[0])), ConversionUtility.Convert <float>(Evaluate(function.Expressions[1])));
                break;

            case "in":
                CheckCase(function, "In");
                CheckExactArgumentCount(function, 2);

                var parameter = Evaluate(function.Expressions[0]);

                var evaluation = false;

                // Goes through any values, and stop whe one is found
                for (var i = 1; i < function.Expressions.Length; i++)
                {
                    var argument = Evaluate(function.Expressions[i]);

                    if (Equals(parameter, argument))
                    {
                        evaluation = true;
                        break;
                    }
                }

                Result = evaluation;
                break;

            default:
                throw new ArgumentException("Function not found", function.Identifier.Name);
            }
        }