public Expression() { AddOperator(new FunOperator("+", 20, true, (v1, v2) => v1 + v2)); AddOperator(new FunStringOperator("++", 20, true, (v1, v2) => v1 + " " + v2)); AddOperator(new FunStringOperator("+++", 20, true, (v1, v2) => v1 + " + " + v2)); AddOperator(new FunStringOperator("%%", 20, true, (v1, v2) => v1 + v2)); AddOperator(new FunOperator("-", 20, true, (v1, v2) => v1 - v2)); AddOperator(new FunOperator("*", 30, true, (v1, v2) => v1 * v2)); AddOperator(new FunOperator("/", 30, true, (v1, v2) => v1 / v2)); AddOperator(new FunOperator("%", 30, true, (v1, v2) => v1 % v2)); AddOperator(new FunOperator("^", 40, false, (v1, v2) => Math.Pow(v1, v2))); AddOperator(new FunBoolOperator("&&", 4, false, (v1, v2) => (v1 != 0.0D && v2 != 0.0D))); AddOperator(new FunBoolOperator("||", 2, false, (v1, v2) => (v1 != 0.0D || v2 != 0.0D))); AddOperator(new FunBoolOperator(">", 10, false, (v1, v2) => (v1 > v2))); AddOperator(new FunBoolStringOperator(">>", 10, false, (v1, v2) => v1.Trim().Length > v2.Trim().Length)); AddOperator(new FunBoolOperator(">=", 10, false, (v1, v2) => (v1 >= v2))); AddOperator(new FunBoolOperator("<", 10, false, (v1, v2) => (v1 < v2))); AddOperator(new FunBoolStringOperator("<<", 10, false, (v1, v2) => v1.Trim().Length < v2.Trim().Length)); AddOperator(new FunBoolOperator("<=", 10, false, (v1, v2) => (v1 <= v2))); AddOperator(new FunBoolOperator("=", 7, false, (v1, v2) => (v1 == v2))); AddOperator(new FunBoolStringOperator("==", 7, false, (v1, v2) => v1.Trim().Equals(v2.Trim(), StringComparison.InvariantCultureIgnoreCase))); AddOperator(new FunBoolStringOperator("!=", 7, false, (v1, v2) => !v1.Trim().Equals(v2.Trim(), StringComparison.InvariantCultureIgnoreCase))); AddOperator(new FunBoolOperator("<>", 7, false, (v1, v2) => (v1 != v2))); AddOperator(new FunUnaryOperator("-", 60, false, (v) => v * -1.0D)); AddOperator(new FunUnaryOperator("+", 60, false, (v) => v * +1.0D)); AddOperator(new FunUnaryOperator("!", 60, false, (v) => (v == 0.0D ? 1.0D : 0.0D))); AddFunction(new Fun1PFunction("NOT", (v) => (v == 0.0D ? 1.0D : 0.0D))); AddFunction(new FunNoParamsFunction("RANDOM", () => Random.NextDouble())); AddFunction(new Fun1PFunction("SIN", (v) => Math.Sin(v))); AddFunction(new Fun1PFunction("COS", (v) => Math.Cos(v))); AddFunction(new Fun1PFunction("TAN", (v) => Math.Tan(v))); AddFunction(new Fun1PFunction("ASIN", (v) => Math.Asin(v))); AddFunction(new Fun1PFunction("ACOS", (v) => Math.Acos(v))); AddFunction(new Fun1PFunction("ATAN", (v) => Math.Atan(v))); AddFunction(new Fun1PFunction("RAD", (v) => Math.PI * v / 180.0D)); AddFunction(new Fun1PFunction("DEG", (v) => v * (180.0 / Math.PI))); AddFunction(new FunFunction("MAX", (vv) => vv.Max())); AddFunction(new FunFunction("MIN", (vv) => vv.Min())); AddFunction(new FunFunction("SUM", (vv) => vv.Sum())); AddFunction(new FunFunction("AVG", (vv) => vv.Average())); AddFunction(new Fun1PFunction("ABS", (v) => Math.Abs(v))); AddFunction(new Fun1PFunction("LN", v => Math.Log(v))); AddFunction(new Fun1PFunction("LOG10", v => Math.Log10(v))); AddFunction(new Fun2PFunction("LOG", (v, b) => Math.Log(v, b))); AddFunction(new Fun1PFunction("ROUND", (v) => Math.Round(v))); AddFunction(new Fun1PFunction("FLOOR", (v) => Math.Floor(v))); AddFunction(new Fun1PFunction("CEIL", (v) => Math.Ceiling(v))); AddFunction(new Fun1PFunction("SQRT", (v) => Math.Sqrt(v))); AddLazyFunction(new FunIf()); AddLazyFunction(new FunIfBreak()); AddLazyFunction(new FunLazyFunction("JOIN", (parms) => new FunLazyNumberA(() => { List <double> joined = new List <double>(); parms.ForEach(n => joined.AddRange(n.EvalArray())); return(joined.ToArray()); }) )); AddLazyFunction(new FunLazyFunction("CONCAT", (parms) => { FunLazyString tmp = new FunLazyString(() => { StringBuilder joined = new StringBuilder(); parms.ForEach(n => joined.Append(n.EvalString())); return(joined.ToString()); }); return(tmp); } )); AddLazyFunction(new FunLazyFunction("SORT", (parms) => { FunLazyNumberA tmp = new FunLazyNumberA(() => { if (parms.Count() == 0) { return(new double[0]); } if (parms.Count() == 1) { return(parms[0].EvalArray().OrderBy(v => v).ToArray()); } return(parms.SelectMany(v => v.EvalArray()).OrderBy(d => d).ToArray()); }); return(tmp); } )); AddLazyFunction(new FunLazyFunction("STRLEN", (parms) => new FunLazyNumberS(() => parms.Select(n => n.EvalString().Length).Sum()))); AddLazyFunction(new FunLazyFunction("STRCMP", (parms) => new FunLazyNumberS(() => parms.All(n => n.EvalString().Equals(parms.First().EvalString(), StringComparison.InvariantCulture))))); AddLazyFunction(new FunLazyFunction("STRICMP", (parms) => new FunLazyNumberS(() => parms.All(n => n.EvalString().Equals(parms.First().EvalString(), StringComparison.InvariantCultureIgnoreCase))))); AddLazyFunction(new FunLazyFunction("IN", (parms) => new FunLazyNumberS(() => { var parm0 = parms[0].EvalString(); var oparms = parms.Skip(1); return(oparms.Any(p => p.EvalString().Equals(parm0))); }))); AddLazyFunction(new RNGPERC()); variables.Add("e", e); variables.Add("PI", PI); variables.Add("NaN", double.NaN); variables.Add("null", double.NaN); variables.Add("TRUE", 1.0D); variables.Add("FALSE", 0.0D); }
private LazyNumber LazyEval(string expression) { if (string.IsNullOrEmpty(expression)) { throw new ExpressionException("Empty expression"); } Stack <LazyNumber> stack = new Stack <LazyNumber>(); foreach (Token token in GetRPN(expression)) { switch (token.type) { case TokenType.UNARY_OPERATOR: LazyNumber value = stack.Pop(); stack.Push(operators[token.surface].Eval(value, null)); break; case TokenType.OPERATOR: LazyNumber v2 = stack.Pop(); LazyNumber v1 = stack.Pop(); stack.Push(operators[token.surface].Eval(v1, v2)); break; case TokenType.VARIABLE: LazyNumber lazyNumber; if (variables.ContainsKey(token.surface)) { lazyNumber = new FunLazyNumberS(() => variables[token.surface]); } else { if (vararrays.ContainsKey(token.surface)) { lazyNumber = new FunLazyNumberA(() => vararrays[token.surface]); } else { if (stringVariables.ContainsKey(token.surface)) { lazyNumber = new FunLazyString(() => stringVariables[token.surface]); } else { throw new UnknownVariableInExpressionException("Unknown variable: " + token.ToString(), token.ToString()); } } } stack.Push(lazyNumber); break; case TokenType.OBJPATH: if (!string.IsNullOrEmpty(token.surface)) { LazyNumber avar = stack.Peek(); if (avar is FunLazyString) { var lazyjson = new FunLazyJSON((FunLazyString)avar) { ObjectPath = token.surface }; stack.Pop(); stack.Push(lazyjson); } else { throw new ExpressionException("Object path set to a variable that is not a JSON object"); } } else { throw new ExpressionException("Empty or invalid object path"); } break; case TokenType.FUNCTION: bool isMap = false, isReduce = false; string s = token.surface; if (s[0] == MapChar) { s = s.Substring(1); isMap = true; } if (s[0] == ReduceChar) { s = s.Substring(1); isReduce = true; } LazyFunction f = functions[s]; List <LazyNumber> p = new List <LazyNumber>( !f.NumParamsVaries() ? f.NumParams : 0); // pop parameters off the stack until we hit the start of // this function's parameter list while (!stack.IsEmpty() && stack.Peek() != PARAMS_START) { p.Insert(0, stack.Pop()); } if (stack.Peek() == PARAMS_START) { stack.Pop(); } LazyNumber fResult; if (isMap) { fResult = new FunLazyNumberA(() => { double[] vals = p[0].EvalArray(); if (vals.Length == 0) { return(new double[0]); } double[] res = new double[vals.Length]; int i = 0; foreach (double val in vals) { p[0] = new FunLazyNumberS(() => val); res[i++] = f.LazyEval(p).Eval(); } return(res); }); } else { if (isReduce) { fResult = new FunLazyNumberS(() => { double[] vals = p[0].EvalArray(); if (vals.Length == 0) { return(0.0D); } if (vals.Length == 1) { return(vals[0]); } double res = 0.0D; List <LazyNumber> pred = new List <LazyNumber>(p.Count + 1) { // collection initialization ... ugly ....:) null, null }; if (p.Count > 1) { pred.AddRange(p.GetRange(1, p.Count - 1)); } pred[0] = new FunLazyNumberS(() => vals[0]); pred[1] = new FunLazyNumberS(() => vals[1]); res = f.LazyEval(pred).Eval(); for (int i = 2; i < vals.Length; i++) { pred[0] = new FunLazyNumberS(() => res); pred[1] = new FunLazyNumberS(() => vals[i]); res = f.LazyEval(pred).Eval(); } return(res); }); } else { fResult = f.LazyEval(p); } } stack.Push(fResult); break; case TokenType.OPEN_PAREN: stack.Push(PARAMS_START); break; case TokenType.LITERAL: stack.Push(new FunLazyNumberS(() => StoD(token.surface))); break; case TokenType.STRINGPARAM: FunLazyString tmpNumber = new FunLazyString(() => token.surface); stack.Push(tmpNumber); break; case TokenType.HEX_LITERAL: double hexd = double.NaN; try { hexd = (double)Convert.ToInt64(token.surface, 16); } catch (Exception) { } // no need to worry, just NaN stack.Push(new FunLazyNumberS(() => hexd)); break; } } return(stack.Pop()); }