コード例 #1
0
        public CompileRpn(
            Rpn rpn,
            List <NameAndType> entityFields = null)
        {
            _original = rpn.Result.ToList();

            var operatorEvaluator = new Dictionary <Operator, Action <ILGenerator> >
            {
                { Operator.Negation, _ => _.Emit(OpCodes.Neg) },
                { Operator.Not, _ => _.Emit(OpCodes.Not) },
                { Operator.Division, _ => _.Emit(OpCodes.Div) },
                { Operator.Minus, _ => _.Emit(OpCodes.Sub) },
                { Operator.Multiplication, _ => _.Emit(OpCodes.Mul) },
                { Operator.Addition, _ => _.Emit(OpCodes.Add) }, // how to handle strings?
                { Operator.And, _ => _.Emit(OpCodes.And) },
                { Operator.Or, _ => _.Emit(OpCodes.Or) },
                { Operator.Equal, _ => _.Emit(OpCodes.Ceq) },
                { Operator.Lt, _ => _.Emit(OpCodes.Clt) },
                { Operator.Gt, _ => _.Emit(OpCodes.Cgt) },
                {
                    Operator.NotEqual, _ =>
                    {
                        _.Emit(OpCodes.Ceq);
                        _.Emit(OpCodes.Ldc_I4_0);
                        _.Emit(OpCodes.Ceq);
                    }
                },
                {
                    Operator.EqGt, _ =>
                    {
                        _.Emit(OpCodes.Clt);
                        _.Emit(OpCodes.Ldc_I4_0);
                        _.Emit(OpCodes.Ceq);
                    }
                },
                {
                    Operator.EqLt, _ =>
                    {
                        _.Emit(OpCodes.Cgt);
                        _.Emit(OpCodes.Ldc_I4_0);
                        _.Emit(OpCodes.Ceq);
                    }
                },
                //{Operator.Question, calcQuestion},
            };

            _operatorEvaluator = new Action <ILGenerator> [operatorEvaluator.Keys.Max(_ => (int)_) + 1];
            foreach (var p in operatorEvaluator)
            {
                _operatorEvaluator[(int)p.Key] = p.Value;
            }

            var method = new DynamicMethod("", typeof(object), new[] { typeof(object[]) }, GetType().Module);
            var il     = method.GetILGenerator();

            var typeStack = new Stack <Type>();

            foreach (var item in _original)
            {
                var itemNumeric = item as RpnItemOperandNumeric;
                if (itemNumeric != null)
                {
                    il.Emit(OpCodes.Ldc_R8, itemNumeric.Numeric);
                    typeStack.Push(typeof(double));
                    continue;
                }

                var itemOperator = item as RpnItemOperator;
                if (itemOperator != null)
                {
                    if (itemOperator.IsUnary())
                    {
                        typeStack.Pop();
                    }
                    else
                    {
                        typeStack.Pop();
                        typeStack.Pop();
                    }
                    operatorEvaluator[itemOperator.Operator](il);
                    typeStack.Push(typeof(double));
                    continue;
                }

                var itemVariable = item as RpnItemOperandVariable;
                if (itemVariable != null)
                {
                    var x = entityFields.FindIndex(_ => _.Name == itemVariable.Name);
                    if (x < 0)
                    {
                        throw new ArgumentException($"Unknown varable '{itemVariable.Name}'");
                    }
                    if (entityFields[x].Type != typeof(double))
                    {
                        throw new NotImplementedException();
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldc_I4, x);
                        il.Emit(OpCodes.Ldelem_Ref);
                        il.Emit(OpCodes.Unbox_Any, typeof(double));
                    }
                    //_original[i] = new RpnItemOperandNumeric2(() => (_variables[x] as IConvertible)?.ToDouble(null) ?? 0);
                    typeStack.Push(typeof(double));
                    continue;
                }

                throw new Exception("What the hell happened here?");
            }

            if (typeStack.Count != 1)
            {
                throw new Exception("What the hell happened here?");
            }

            il.Emit(OpCodes.Box, typeof(double));
            il.Emit(OpCodes.Ret);

            Evaluate = (Func <object[], object>)method.CreateDelegate(typeof(Func <object[], object>));
        }
コード例 #2
0
        public EvaluateRpn(
            Rpn rpn,
            List <NameAndType> entityFields = null)
        {
            _functions = new Dictionary <string, FunctionDescriptor>
            {
                { "min", new FunctionDescriptor(-1, funcMin, typeof(double)) },
                { "max", new FunctionDescriptor(-1, funcMax, typeof(double)) },
                { "first", new FunctionDescriptor(-1, funcFirst, typeof(string)) },
                { "str", new FunctionDescriptor(1, (stack, args) => push(stack, stack.Pop().String), typeof(string)) },
                { "val", new FunctionDescriptor(1, (stack, args) => push(stack, stack.Pop().Numeric), typeof(double)) },
                { "int", new FunctionDescriptor(1, (stack, args) => push(stack, (int)stack.Pop().Numeric), typeof(double)) },
                { "len", new FunctionDescriptor(1, (stack, args) => push(stack, stack.Pop().String?.Length), typeof(double)) },
            };

            _original = rpn.Result.ToList();

            var operatorEvaluator = new Dictionary <Operator, Action <Stack <RpnItemOperand> > >
            {
                { Operator.Negation, stack => calcUnary(stack, x => - x) },
                { Operator.Not, stack => calcUnary(stack, x => x != 0 ? 1 : 0) },
                { Operator.Division, stack => calcBinary(stack, (x, y) => x / y) },
                { Operator.Mod, stack => calcBinary(stack, (x, y) => (int)x % (int)y) },
                { Operator.Minus, stack => calcBinary(stack, (x, y) => x - y) },
                { Operator.Multiplication, stack => calcBinary(stack, (x, y) => x * y) },
                { Operator.Addition, stack => calcBinary(stack, (x, y) => x + y) },
                { Operator.Concat, concat },
                { Operator.And, stack => calcBinary(stack, (x, y) => (x != 0) && (y != 0) ? 1 : 0) },
                { Operator.Or, stack => calcBinary(stack, (x, y) => (x != 0) || (y != 0) ? 1 : 0) },
                { Operator.Question, calcQuestion },
                { Operator.NullCoalescing, calcNullCoalescing },
                {
                    Operator.Equal, stack => calcBinary(stack, (x, y) => x == y ? 1 : 0,
                                                        (x, y) => new RpnItemOperandNumeric(string.CompareOrdinal(x, y) == 0 ? 1 : 0))
                },
                {
                    Operator.Lt, stack => calcBinary(stack, (x, y) => x < y ? 1 : 0,
                                                     (x, y) => new RpnItemOperandNumeric(string.CompareOrdinal(x, y) < 0 ? 1 : 0))
                },
                {
                    Operator.EqLt, stack => calcBinary(stack, (x, y) => x <= y ? 1 : 0,
                                                       (x, y) => new RpnItemOperandNumeric(string.CompareOrdinal(x, y) <= 0 ? 1 : 0))
                },
                {
                    Operator.Gt, stack => calcBinary(stack, (x, y) => x > y ? 1 : 0,
                                                     (x, y) => new RpnItemOperandNumeric(string.CompareOrdinal(x, y) > 0 ? 1 : 0))
                },
                {
                    Operator.EqGt, stack => calcBinary(stack, (x, y) => x >= y ? 1 : 0,
                                                       (x, y) => new RpnItemOperandNumeric(string.CompareOrdinal(x, y) >= 0 ? 1 : 0))
                },
                {
                    Operator.NotEqual, stack => calcBinary(stack, (x, y) => x != y ? 1 : 0,
                                                           (x, y) => new RpnItemOperandNumeric(string.CompareOrdinal(x, y) != 0 ? 1 : 0))
                },
            };

            if (entityFields != null)
            {
                for (var i = 0; i < _original.Count; i++)
                {
                    var itm = _original[i] as RpnItemOperandVariable;
                    if (itm == null)
                    {
                        continue;
                    }
                    var x = entityFields.FindIndex(_ => _.Name == itm.Name);
                    if (x < 0)
                    {
                        throw new ArgumentException($"Unknown varable '{itm.Name}'");
                    }
                    _original[i] = new RpnIndexedVariable(x, entityFields[x].Type);
                }
            }

            typeEval();

            for (var i = 0; i < _original.Count; i++)
            {
                var itmOperator = _original[i] as RpnItemOperator;
                if (itmOperator != null)
                {
                    Action <Stack <RpnItemOperand> > action = stack => operatorEvaluator[itmOperator.Operator](stack);
                    _original[i] = new RpnItemAction {
                        Action = action
                    };
                    continue;
                }
                var itmFunction = _original[i] as RpnItemFunction;
                if (itmFunction != null)
                {
                    var argumentCount = itmFunction.ArgumentCount;
                    var descriptor    = _functions[itmFunction.Name];
                    if (descriptor.NumberOfArguments != -1 && descriptor.NumberOfArguments != argumentCount)
                    {
                        throw new ArgumentException(
                                  $"Wrong number of arguments to '{itmFunction.Name}' function. Expected {descriptor.NumberOfArguments}, but was {argumentCount}");
                    }
                    Action <Stack <RpnItemOperand> > action = stack => descriptor.Evaluate(stack, argumentCount);
                    _original[i] = new RpnItemAction {
                        Action = action
                    };
                    continue;
                }
            }
        }