/// /// <summary> /// Parses arithmetic expressions /// </summary> /// /// <param name="leftOperand">Left operand</param> /// <param name="rightOperand">Right operand</param> /// <param name="arithType">Arithmetic operator type</param> /// /// <remarks> /// Only works with operands that evaluate to either numeric or string types. If both operands are strings /// and arithType is ADD, concatenation is performed. Else, if either operand is of a float type, both are /// treated as float type. Else, both are treated as int types. This is to ensure proper behavior of operators /// such as addition and division. If operands are of int type, result is then parsed as a literal expression /// to ensure correct return type. /// </remarks> /// /// <returns>Result of arithmetic operation</returns> /// /// <exception cref="CseLogicExceptionType.ARITH_EXCEPTION" /> /// <exception cref="CseLogicExceptionType.LEFT_OP_NON_NUM" /> /// <exception cref="CseLogicExceptionType.RIGHT_OP_NON_NUM" /> /// internal static CseObject Parse(CseObject leftOperand, CseObject rightOperand, ArithType arithType) { dynamic result = null; dynamic leftOpValue = leftOperand.Value; dynamic rightOpValue = rightOperand.Value; string methOpName = null; try { switch (arithType) { case ArithType.ADD: methOpName = OpOverloadNames.ADD; result = leftOpValue + rightOpValue; break; case ArithType.DIV: methOpName = OpOverloadNames.DIV; result = leftOpValue / rightOpValue; break; case ArithType.MOD: methOpName = OpOverloadNames.MOD; result = leftOpValue % rightOpValue; break; case ArithType.MUL: methOpName = OpOverloadNames.MUL; result = leftOpValue * rightOpValue; break; case ArithType.POW: result = Math.Pow(leftOpValue, rightOpValue); break; case ArithType.SUB: methOpName = OpOverloadNames.SUB; result = leftOpValue - rightOpValue; break; } return(new CseObject(result)); } catch { if (methOpName == null) { throw new CseLogicException(CseLogicExceptionType.ARITH_EXCEPTION, leftOpValue, rightOpValue); } MethodInfo leftOpMeth = leftOpValue.GetType().GetMethod(methOpName, OpOverloadNames.Flags); MethodInfo rightOpMeth = rightOpValue.GetType().GetMethod(methOpName, OpOverloadNames.Flags); if (leftOpMeth == null && rightOpMeth == null) { throw new CseLogicException(CseLogicExceptionType.ARITH_EXCEPTION, leftOpValue, rightOpValue); } else if (leftOpMeth != null) { try { result = new CseObject(leftOpMeth.Invoke(leftOpValue, new object[] { leftOpValue, rightOpValue })); } catch { throw new CseLogicException(CseLogicExceptionType.ARITH_EXCEPTION, leftOpValue, rightOpValue); } } else if (rightOpMeth != null) { try { result = new CseObject(rightOpMeth.Invoke(rightOpValue, new object[] { leftOpValue, rightOpValue })); } catch { throw new CseLogicException(CseLogicExceptionType.ARITH_EXCEPTION, leftOpValue, rightOpValue); } } else { throw new CseLogicException(CseLogicExceptionType.ARITH_EXCEPTION, leftOpValue, rightOpValue); } } return(new CseObject(result)); }
/// /// <summary> /// Parses arithmetic expressions /// </summary> /// /// <param name="leftOperand">Left operand</param> /// <param name="rightOperand">Right operand</param> /// <param name="arithType">Arithmetic operator type</param> /// /// <remarks> /// Only works with operands that evaluate to either numeric or string types. If both operands are strings /// and arithType is ADD, concatenation is performed. Else, if either operand is of a float type, both are /// treated as float type. Else, both are treated as int types. This is to ensure proper behavior of operators /// such as addition and division. If operands are of int type, result is then parsed as a literal expression /// to ensure correct return type. /// </remarks> /// /// <returns>Result of arithmetic operation</returns> /// /// <exception cref="CseLogicExceptionType.ARITH_EXCEPTION" /> /// <exception cref="CseLogicExceptionType.LEFT_OP_NON_NUM" /> /// <exception cref="CseLogicExceptionType.RIGHT_OP_NON_NUM" /> /// internal static CseObject Parse(CseObject leftOperand, CseObject rightOperand, ArithType arithType) { dynamic result = null; dynamic leftOpValue = leftOperand.Value; dynamic rightOpValue = rightOperand.Value; string methOpName = null; try { switch (arithType) { case ArithType.ADD: methOpName = OpOverloadNames.ADD; result = leftOpValue + rightOpValue; break; case ArithType.DIV: methOpName = OpOverloadNames.DIV; result = leftOpValue / rightOpValue; break; case ArithType.MOD: methOpName = OpOverloadNames.MOD; result = leftOpValue % rightOpValue; break; case ArithType.MUL: methOpName = OpOverloadNames.MUL; result = leftOpValue * rightOpValue; break; case ArithType.POW: result = Math.Pow(leftOpValue, rightOpValue); break; case ArithType.SUB: methOpName = OpOverloadNames.SUB; result = leftOpValue - rightOpValue; break; } return new CseObject(result); } catch { if (methOpName == null) throw new CseLogicException(CseLogicExceptionType.ARITH_EXCEPTION, leftOpValue, rightOpValue); MethodInfo leftOpMeth = leftOpValue.GetType().GetMethod(methOpName, OpOverloadNames.Flags); MethodInfo rightOpMeth = rightOpValue.GetType().GetMethod(methOpName, OpOverloadNames.Flags); if (leftOpMeth == null && rightOpMeth == null) throw new CseLogicException(CseLogicExceptionType.ARITH_EXCEPTION, leftOpValue, rightOpValue); else if (leftOpMeth != null) { try { result = new CseObject(leftOpMeth.Invoke(leftOpValue, new object[] { leftOpValue, rightOpValue })); } catch { throw new CseLogicException(CseLogicExceptionType.ARITH_EXCEPTION, leftOpValue, rightOpValue); } } else if (rightOpMeth != null) { try { result = new CseObject(rightOpMeth.Invoke(rightOpValue, new object[] { leftOpValue, rightOpValue })); } catch { throw new CseLogicException(CseLogicExceptionType.ARITH_EXCEPTION, leftOpValue, rightOpValue); } } else { throw new CseLogicException(CseLogicExceptionType.ARITH_EXCEPTION, leftOpValue, rightOpValue); } } return new CseObject(result); }