예제 #1
0
        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);
        }
예제 #2
0
        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());
        }