/// <summary> /// Takes two TNumbers and subtracts one from the other. /// </summary> /// <param name="interpreter">The interpreter that the method is being called from.</param> /// <param name="a">The left hand operand of the operation.</param> /// <param name="b">The right hand operand of the operation.</param> /// <returns> /// The TType resulting from the operation. An MExcpetion or null is returned when there is an error. /// </returns> public static TType Subtract(Interpreter interpreter, TType a, TType b) { // Try to get TNumber values from the TType arguments TNumber numberA, numberB; TException exception = AssignNumberValue(interpreter, out numberA, a); if (exception != null) return exception; exception = AssignNumberValue(interpreter, out numberB, b); if (exception != null) return exception; // No errors, but one or both of the arguments could be a TString; check them if ((numberA == null) || (numberB == null)) return new TException(interpreter, "Strings cannot be used in subtraction operations"); switch (numberA.TypeName) { case TType.T_INTEGER_TYPENAME: { // If the other operand is a fraction, treat this integer as a fraction (i.e. value/1) TFraction rhsFraction = numberB as TFraction; if (rhsFraction != null) { // Order of fractions matters in this case TFraction lhsFraction = new TFraction(numberA.TIntegerValue, 1); lhsFraction.Subtract(rhsFraction.Numerator, rhsFraction.Denominator); return lhsFraction; } return new TInteger(numberA.TIntegerValue - numberB.TIntegerValue); } case TType.T_REAL_TYPENAME: return new TReal(numberA.TRealValue - numberB.TRealValue); case TType.T_FRACTION_TYPENAME: { // Create a copy of the left hand fraction TFraction fraction = numberA as TFraction; fraction = new TFraction(fraction.Numerator, fraction.Denominator); // Convert the right hand operand to a fraction long numerator, denominator; TFraction otherFraction = numberB as TFraction; if (otherFraction != null) // If it's a fraction, simply copy the values { numerator = otherFraction.Numerator; denominator = otherFraction.Denominator; } else { // Check if it's a TInteger first. It might not need to use DoubleToFraction if (numberB is TInteger) { numerator = numberB.TIntegerValue; denominator = 1; } else Operations.Misc.DoubleToFraction(numberB.TRealValue, out numerator, out denominator); } fraction.Subtract(numerator, denominator); return fraction; } } return null; }
/// <summary> /// Takes two TNumbers or two TStrings (or up to two TVariables containing TNumbers or TStrings) and /// adds them together. /// </summary> /// <param name="interpreter">The interpreter that the method is being called from.</param> /// <param name="a">The left hand operand of the operation.</param> /// <param name="b">The right hand operand of the operation.</param> /// <returns> /// The TType resulting from the operation. An MExcpetion or null is returned when there is an error. /// </returns> public static TType Add(Interpreter interpreter, TType a, TType b) { // Convert arguments 'a' and 'b' into either a TNumber or a TString TNumber numberA, numberB; TString strA = null, strB = null; TException exception = AssignNumberValue(interpreter, out numberA, a); if (exception != null) return exception; if (numberA == null) { // No errors yet, and numberA is null, so argument 'a' could be a TString or a TVariable // containing a TString strA = a as TString; if (strA == null) { TVariable variable = a as TVariable; if (variable != null) strA = variable.Value as TString; } } if ((numberA == null) && (strA == null)) // Nothing useful, return a TException return new TException(interpreter, "Value is not a number or string"); // Same procedure for argument 'b' exception = AssignNumberValue(interpreter, out numberB, b); if (exception != null) return exception; if (numberB == null) { strB = b as TString; if (strB == null) { TVariable variable = b as TVariable; if (variable != null) strB = variable.Value as TString; } } if ((numberB == null) && (strB == null)) return new TException(interpreter, "Value is not a number or string"); // Attempt addition if both operands are the same type, otherwise return a TException if ((numberB == null) && (strA == null)) return new TException(interpreter, "Attempted addition of a string to a number"); else if ((numberA == null) && (strB == null)) return new TException(interpreter, "Attempted addition of a number to a string"); else if ((numberA == null) && (numberB == null)) { return new TString(strA.Value + strB.Value); } else { //The left hand operand decides the type of the returned value switch (numberA.TypeName) { case TType.T_INTEGER_TYPENAME: { // If the other operand is a fraction, treat this integer as a fraction (i.e. value/1) TFraction fraction = numberB as TFraction; if (fraction != null) { // Copy the right hand fraction and add the left hand integer to it fraction = new TFraction(fraction.Numerator, fraction.Denominator); fraction.Add(numberA.TIntegerValue, 1); return fraction; } return new TInteger(numberA.TIntegerValue + numberB.TIntegerValue); } case TType.T_REAL_TYPENAME: return new TReal(numberA.TRealValue + numberB.TRealValue); case TType.T_FRACTION_TYPENAME: { // Create a copy of the left hand fraction TFraction fraction = numberA as TFraction; fraction = new TFraction(fraction.Numerator, fraction.Denominator); // Convert the right hand operand to a fraction long numerator, denominator; TFraction otherFraction = numberB as TFraction; if (otherFraction != null) // If it's a fraction, simply copy the values { numerator = otherFraction.Numerator; denominator = otherFraction.Denominator; } else { // Check if it's a TInteger first. It might not need to use DoubleToFraction if (numberB is TInteger) { numerator = numberB.TIntegerValue; denominator = 1; } else Operations.Misc.DoubleToFraction(numberB.TRealValue, out numerator, out denominator); } fraction.Add(numerator, denominator); return fraction; } } } return null; }