public override void Visit(Function 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 (int 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 bool found = OnValidateFunction(IgnoreCase ? function.Identifier.Name.ToLower() : function.Identifier.Name, args); string[][] tempVariables = null; // validate builtin function if (!found) { string functionName = function.Identifier.Name.ToLower(); if (BuiltinFunctions.Has(functionName)) { BuiltinFunctions.Validate(functionName, function); found = true; tempVariables = BuiltinFunctions.TempVariables(functionName); } } if (!found) { // function not found OR parameter is invalid throw new Exception("Function \"" + function.Identifier.Name + "\" not defined"); } Result.Append(function.Identifier.Name); Result.Append("("); for (int i = 0; i < function.Expressions.Length; i++) { string[] tempVars = null; if (tempVariables != null && i < tempVariables.Length) { tempVars = tempVariables[i]; if (tempVars != null) { foreach (string var in tempVars) { this.Parameters[var] = new RawIdentifierExpression(var); } } } function.Expressions[i].Accept(this); if (tempVars != null) { foreach (string var in tempVars) { this.Parameters.Remove(var); } } if (i < function.Expressions.Length - 1) { Result.Append(","); } } // trim spaces before adding a closing paren while (Result[Result.Length - 1] == ' ') { Result.Remove(Result.Length - 1, 1); } Result.Append(")"); }
public override void Visit(Function function) { // if raw result is preferred, display functions as it is if ((Options & EvaluateOptions.RawResult) == EvaluateOptions.RawResult) { throw new RawExpressionException(); } 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 (int 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; } string functionName = function.Identifier.Name.ToLower(); if (BuiltinFunctions.Has(functionName)) { Result = BuiltinFunctions.ValidateAndEvaluate(functionName, function, this); } else { throw new ArgumentException("Function not found", function.Identifier.Name); } /* * switch (function.Identifier.Name.ToLower()) * { #region Abs * case "abs": * * CheckCase("Abs", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Abs() takes exactly 1 argument"); * * Result = Math.Abs(Convert.ToDecimal( * Evaluate(function.Expressions[0])) * ); * * break; * #endregion * #region Acos * case "acos": * * CheckCase("Acos", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Acos() takes exactly 1 argument"); * * Result = Math.Acos(Convert.ToDouble(Evaluate(function.Expressions[0]))); * * break; * #endregion * #region Asin * case "asin": * * CheckCase("Asin", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Asin() takes exactly 1 argument"); * * Result = Math.Asin(Convert.ToDouble(Evaluate(function.Expressions[0]))); * * break; * #endregion * #region Atan * case "atan": * * CheckCase("Atan", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Atan() takes exactly 1 argument"); * * Result = Math.Atan(Convert.ToDouble(Evaluate(function.Expressions[0]))); * * break; * #endregion * #region Ceiling * case "ceiling": * * CheckCase("Ceiling", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Ceiling() takes exactly 1 argument"); * * Result = Math.Ceiling(Convert.ToDouble(Evaluate(function.Expressions[0]))); * * break; * #endregion * #region Cos * * case "cos": * * CheckCase("Cos", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Cos() takes exactly 1 argument"); * * Result = Math.Cos(Convert.ToDouble(Evaluate(function.Expressions[0]))); * * break; * #endregion * #region Exp * case "exp": * * CheckCase("Exp", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Exp() takes exactly 1 argument"); * * Result = Math.Exp(Convert.ToDouble(Evaluate(function.Expressions[0]))); * * break; * #endregion * #region Floor * case "floor": * * CheckCase("Floor", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Floor() takes exactly 1 argument"); * * Result = Math.Floor(Convert.ToDouble(Evaluate(function.Expressions[0]))); * * break; * #endregion * #region IEEERemainder * case "ieeeremainder": * * CheckCase("IEEERemainder", function.Identifier.Name); * * if (function.Expressions.Length != 2) * throw new ArgumentException("IEEERemainder() takes exactly 2 arguments"); * * Result = Math.IEEERemainder(Convert.ToDouble(Evaluate(function.Expressions[0])), Convert.ToDouble(Evaluate(function.Expressions[1]))); * * break; * #endregion * #region Log * case "log": * * CheckCase("Log", function.Identifier.Name); * * if (function.Expressions.Length != 2) * throw new ArgumentException("Log() takes exactly 2 arguments"); * * Result = Math.Log(Convert.ToDouble(Evaluate(function.Expressions[0])), Convert.ToDouble(Evaluate(function.Expressions[1]))); * * break; * #endregion * #region Log10 * case "log10": * * CheckCase("Log10", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Log10() takes exactly 1 argument"); * * Result = Math.Log10(Convert.ToDouble(Evaluate(function.Expressions[0]))); * * break; * #endregion * #region Pow * case "pow": * * CheckCase("Pow", function.Identifier.Name); * * if (function.Expressions.Length != 2) * throw new ArgumentException("Pow() takes exactly 2 arguments"); * * Result = Math.Pow(Convert.ToDouble(Evaluate(function.Expressions[0])), Convert.ToDouble(Evaluate(function.Expressions[1]))); * * break; * #endregion * #region Round * case "round": * * CheckCase("Round", function.Identifier.Name); * * if (!(function.Expressions.Length == 2 || function.Expressions.Length == 1)) * throw new ArgumentException("Round() takes 1 or 2 arguments"); * * int digits = 0; * if (function.Expressions.Length == 2) * { * digits = Convert.ToInt16(Evaluate(function.Expressions[1])); * } * * MidpointRounding rounding = (_options & EvaluateOptions.RoundAwayFromZero) == EvaluateOptions.RoundAwayFromZero ? MidpointRounding.AwayFromZero : MidpointRounding.ToEven; * * Result = Math.Round(Convert.ToDouble(Evaluate(function.Expressions[0])), digits, rounding); * * break; * #endregion * #region Sign * case "sign": * * CheckCase("Sign", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Sign() takes exactly 1 argument"); * * Result = Math.Sign(Convert.ToDouble(Evaluate(function.Expressions[0]))); * * break; * #endregion * #region Sin * case "sin": * * CheckCase("Sin", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Sin() takes exactly 1 argument"); * * Result = Math.Sin(Convert.ToDouble(Evaluate(function.Expressions[0]))); * * break; * #endregion * #region Sqrt * case "sqrt": * * CheckCase("Sqrt", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Sqrt() takes exactly 1 argument"); * * Result = Math.Sqrt(Convert.ToDouble(Evaluate(function.Expressions[0]))); * * break; * #endregion * #region Tan * case "tan": * * CheckCase("Tan", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Tan() takes exactly 1 argument"); * * Result = Math.Tan(Convert.ToDouble(Evaluate(function.Expressions[0]))); * * break; * #endregion * #region Truncate * case "truncate": * * CheckCase("Truncate", function.Identifier.Name); * * if (function.Expressions.Length != 1) * throw new ArgumentException("Truncate() takes exactly 1 argument"); * * Result = Math.Truncate(Convert.ToDouble(Evaluate(function.Expressions[0]))); * * break; * #endregion * #region Max * case "max": * * CheckCase("Max", function.Identifier.Name); * * if (function.Expressions.Length != 2) * throw new ArgumentException("Max() takes exactly 2 arguments"); * * object maxleft = Evaluate(function.Expressions[0]); * object maxright = Evaluate(function.Expressions[1]); * * Result = Numbers.Max(maxleft, maxright); * break; * #endregion * #region Min * case "min": * * CheckCase("Min", function.Identifier.Name); * * if (function.Expressions.Length != 2) * throw new ArgumentException("Min() takes exactly 2 arguments"); * * object minleft = Evaluate(function.Expressions[0]); * object minright = Evaluate(function.Expressions[1]); * * Result = Numbers.Min(minleft, minright); * break; * #endregion * #region if * case "if": * * CheckCase("if", function.Identifier.Name); * * if (function.Expressions.Length != 3) * throw new ArgumentException("if() takes exactly 3 arguments"); * * bool cond = Convert.ToBoolean(Evaluate(function.Expressions[0])); * * Result = cond ? Evaluate(function.Expressions[1]) : Evaluate(function.Expressions[2]); * break; * #endregion * #region in * case "in": * * CheckCase("in", function.Identifier.Name); * * if (function.Expressions.Length < 2) * throw new ArgumentException("in() takes at least 2 arguments"); * * object parameter = Evaluate(function.Expressions[0]); * * bool evaluation = false; * * // Goes through any values, and stop whe one is found * for (int i = 1; i < function.Expressions.Length; i++) * { * object argument = Evaluate(function.Expressions[i]); * if (CompareUsingMostPreciseType(parameter, argument) == 0) * { * evaluation = true; * break; * } * } * * Result = evaluation; * break; * #endregion * * default: * throw new ArgumentException("Function not found", * function.Identifier.Name); * }*/ }