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>)); }
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; } } }