/// <summary>
        /// Parses the logical comparisons of the group. Replaces the operators and operands in the group with their
        /// results.
        /// </summary>
        /// <param name="group">The group to parse.</param>
        /// <returns>A TException on failure, otherwise null.</returns>
        TException ParseComparisonsOfGroup(Group group)
        {
            int index;
            while ((index = group.IndexOf("=")) >= 0)
            {
                if ((index - 1 < 0) || (index + 1 >= group.Count))
                    return new TException(this, "Invalid expression term '='");

                TType a = TType.Parse(this, group[index - 1]);
                if (a is TException) return a as TException;
                TType b = TType.Parse(this, group[index + 1]);
                if (b is TException) return b as TException;

                TType result = Operations.Equal(this, a, b, true);
                if (result == null) return new TException(this, "Comparison operation failed", "reason unknown");
                if (result is TException) return result as TException;
                group[index - 1] = result;
                group.RemoveRange(index, 2);
            }

            while ((index = group.IndexOf("~=")) >= 0) // Approximately equal (by rounding or within ~0.5)
            {
                if ((index - 1 < 0) || (index + 1 >= group.Count))
                    return new TException(this, "Invalid expression term '~='");

                TType a = TType.Parse(this, group[index - 1]);
                if (a is TException) return a as TException;
                TType b = TType.Parse(this, group[index + 1]);
                if (b is TException) return b as TException;

                TType result = Operations.Equal(this, a, b, false);
                if (result is TException) return result as TException;
                group[index - 1] = result;
                group.RemoveRange(index, 2);
            }

            while ((index = group.IndexOf("/=")) >= 0) // Not equal
            {
                if ((index - 1 < 0) || (index + 1 >= group.Count))
                    return new TException(this, "Invalid expression term '/='");

                TType a = TType.Parse(this, group[index - 1]);
                if (a is TException) return a as TException;
                TType b = TType.Parse(this, group[index + 1]);
                if (b is TException) return b as TException;

                TType result = Operations.NotEqual(this, a, b);
                if (result == null) return new TException(this, "Comparison operation failed", "reason unknown");
                if (result is TException) return result as TException;
                group[index - 1] = result;
                group.RemoveRange(index, 2);
            }

            while ((index = group.IndexOf("<")) >= 0)
            {
                if ((index - 1 < 0) || (index + 1 >= group.Count))
                    return new TException(this, "Invalid expression term '<'");

                TType a = TType.Parse(this, group[index - 1]);
                if (a is TException) return a as TException;
                TType b = TType.Parse(this, group[index + 1]);
                if (b is TException) return b as TException;

                TType result = Operations.Math.Inequality(this, a, b, "<");
                if (result == null) return new TException(this, "Less than comparison failed", "reason unknown");
                if (result is TException) return result as TException;
                group[index - 1] = result;
                group.RemoveRange(index, 2);
            }

            while ((index = group.IndexOf(">")) >= 0)
            {
                if ((index - 1 < 0) || (index + 1 >= group.Count))
                    return new TException(this, "Invalid expression term '<'");

                TType a = TType.Parse(this, group[index - 1]);
                if (a is TException) return a as TException;
                TType b = TType.Parse(this, group[index + 1]);
                if (b is TException) return b as TException;

                TType result = Operations.Math.Inequality(this, a, b, ">");
                if (result == null)
                    return new TException(this, "Greater than comparison failed", "reason unknown");
                if (result is TException) return result as TException;
                group[index - 1] = result;
                group.RemoveRange(index, 2);
            }

            while ((index = group.IndexOf("<=")) >= 0)
            {
                if ((index - 1 < 0) || (index + 1 >= group.Count))
                    return new TException(this, "Invalid expression term '<'");

                TType a = TType.Parse(this, group[index - 1]);
                if (a is TException) return a as TException;
                TType b = TType.Parse(this, group[index + 1]);
                if (b is TException) return b as TException;

                TType result = Operations.Math.Inequality(this, a, b, "<=");
                if (result == null)
                    return new TException(this, "Less than or equal comparison failed", "reason unknown");
                if (result is TException) return result as TException;
                group[index - 1] = result;
                group.RemoveRange(index, 2);
            }

            while ((index = group.IndexOf(">=")) >= 0)
            {
                if ((index - 1 < 0) || (index + 1 >= group.Count))
                    return new TException(this, "Invalid expression term '<'");

                TType a = TType.Parse(this, group[index - 1]);
                if (a is TException) return a as TException;
                TType b = TType.Parse(this, group[index + 1]);
                if (b is TException) return b as TException;

                TType result = Operations.Math.Inequality(this, a, b, ">=");
                if (result == null)
                    return new TException(this, "Greater than or equal comparison failed", "reason unknown");
                if (result is TException) return result as TException;
                group[index - 1] = result;
                group.RemoveRange(index, 2);
            }

            return null;
        }
        /// <summary>
        /// Parses the commas in the group, converting a comma separated list into a TArgumentList, and replacing the
        /// list in the group with it.
        /// </summary>
        /// <param name="group">The group to parse.</param>
        /// <returns>A TException on failure, otherwise null.</returns>
        TException ParseCommasOfGroup(Group group)
        {
            int index;
            while ((index = group.IndexOf(",")) >= 0)
            {
                if ((index - 1 < 0) || (index + 1 >= group.Count))
                    return new TException(this, "Invalid expression term ','");

                TType a = TType.Parse(this, group[index - 1]);
                if (a is TException) return a as TException;
                TType b = TType.Parse(this, group[index + 1]);
                if (b is TException) return b as TException;

                TArgumentList argList = a as TArgumentList;
                if (argList == null)
                {
                    argList = new TArgumentList();
                    argList.Add(a);
                    argList.Add(b);
                }
                else argList.Add(b);

                group[index - 1] = argList;
                group.RemoveRange(index, 2);
            }

            return null;
        }
        /// <summary>
        /// Parses a group, searching for any modulus brackets and replacing the modulus brackets and their contents
        /// with the absolute values.
        /// </summary>
        /// <param name="group">The group to parse.</param>
        /// <returns>A TException on failure, otherwise null.</returns>
        TException ParseModulusBracketsOfGroup(Group group)
        {
            int index;
            while ((index = group.IndexOf(TType.MODULUS_CHARACTER.ToString())) >= 0)
            {
                TException exception = new TException(this, "Modulus brackets not closed", "another | required");
                if (index + 2 >= group.Count) return exception;
                if (group[index + 2] is string)
                {
                    if ((string)group[index + 2] != TType.MODULUS_CHARACTER.ToString()) return exception;
                }
                else return exception;

                TType value = TType.Parse(this, group[index + 1]);
                if (value is TException) return value as TException;

                TType result = Operations.Math.Modulus(this, value);
                if (result == null) return new TException(this, "Modulus operation failed", "reason unknown");
                if (result is TException) return result as TException;
                group[index] = result;
                group.RemoveRange(index + 1, 2);
            }

            return null;
        }
        /// <summary>
        /// Parses all of the arithmetic in the group, according to BIDMAS (although ignoring Brackets, because
        /// they're taken care of elsewhere), replacing the operands and operators with the results.
        /// </summary>
        /// <param name="group">The group to parse.</param>
        /// <returns>A TException on failure, otherwise null.</returns>
        TException ParseBidmasOfGroup(Group group)
        {
            // For every while loop, convert the values either side of the operator to the relevant TType, and attempt
            // to perform the operation on them. Then replace the operands and operator in the group with the result

            int index;
            while ((index = group.IndexOf("^")) >= 0) // Indicies
            {
                if ((index - 1 < 0) || (index + 1 >= group.Count))
                    return new TException(this, "Invalid expression term '^'");

                TType a = TType.Parse(this, group[index - 1]);
                if (a is TException) return a as TException;
                TType b = TType.Parse(this, group[index + 1]);
                if (b is TException) return b as TException;

                TType result = Operations.Math.Pow(this, a, b);
                if (result == null) return new TException(this, "Exponentiation operation failed", "reason unknown");
                if (result is TException) return result as TException;
                group[index - 1] = result;
                group.RemoveRange(index, 2);
            }

            while (true) // Division and Multiplication
            {
                // Find out which operator comes first in order to parse the expression from left to right
                int divIndex = group.IndexOf("/"), mulIndex = group.IndexOf("*");
                if (divIndex < 0) index = mulIndex;
                else if (mulIndex < 0) index = divIndex;
                else index = divIndex < mulIndex ? divIndex : mulIndex;
                if (index < 0) break;

                if ((index - 1 < 0) || (index + 1 >= group.Count))
                    return new TException(this, "Invalid expression term '" + group[index] + "'");

                TType a = TType.Parse(this, group[index - 1]);
                if (a is TException) return a as TException;
                TType b = TType.Parse(this, group[index + 1]);
                if (b is TException) return b as TException;

                TType result;
                if ((string)group[index] == "/")
                {
                    result = Operations.Math.Divide(this, a, b);
                    if (result == null) return new TException(this, "Division operation failed", "reason unknown");
                }
                else
                {
                    result = Operations.Math.Multiply(this, a, b);
                    if (result == null)
                        return new TException(this, "Multiplication operation failed", "reason unknown");
                }

                if (result is TException) return result as TException;
                group[index - 1] = result;
                group.RemoveRange(index, 2);
            }

            while (true) // Addition and Subtraction
            {
                int addIndex = group.IndexOf("+"), subIndex = group.IndexOf("-");
                if (addIndex < 0) index = subIndex;
                else if (subIndex < 0) index = addIndex;
                else index = addIndex < subIndex ? addIndex : subIndex;
                if (index < 0) break;

                char operatorChar = ((string)group[index])[0];

                if (index - 1 < 0)
                { // There's no number before the operator, so perform a unary operation
                    TException exception = ParseUnaryArtitmetic(group, index, operatorChar);
                    if (exception != null) return exception;
                    continue;
                }
                else if (index + 1 >= group.Count)
                    return new TException(this, "Invalid expression term '" + group[index] + "'");

                TType a = TType.Parse(this, group[index - 1]);
                if (a is TException)
                {
                    string possibleOperator = group[index - 1] as string;
                    if (possibleOperator != null)
                    {
                        if (RESERVED_SYMBOLS.Contains(possibleOperator))
                        {
                            TException exception = ParseUnaryArtitmetic(group, index, operatorChar);
                            if (exception != null) return exception;
                            continue;
                        }
                    }
                    return a as TException;
                }
                TType b = TType.Parse(this, group[index + 1]);
                if (b is TException) return b as TException;

                TType result;
                if (operatorChar == '+')
                {
                    result = Operations.Math.Add(this, a, b);
                    if (result == null) return new TException(this, "Addition operation failed", "reason unknown");
                }
                else
                {
                    result = Operations.Math.Subtract(this, a, b);
                    if (result == null) return new TException(this, "Subtraction operation failed", "reason unknown");
                }

                if (result is TException) return result as TException;
                group[index - 1] = result;
                group.RemoveRange(index, 2);
            }

            return null;
        }
        /// <summary>
        /// Parses the logical operators of the group. Replaces the operators and operands with their results.
        /// </summary>
        /// <param name="group">The group to parse.</param>
        /// <returns>A TException on failure, otherwise null.</returns>
        TException ParseLogicalOperatorsOfGroup(Group group)
        {
            int index;
            while ((index = group.IndexOf("and")) >= 0)
            {
                if ((index - 1 < 0) || (index + 1 >= group.Count))
                    return new TException(this, "Invalid expression term ','");

                TType a = TType.Parse(this, group[index - 1]);
                if (a is TException) return a as TException;
                TType b = TType.Parse(this, group[index + 1]);
                if (b is TException) return b as TException;

                TBoolean aBool = a as TBoolean;
                if (aBool == null)
                    return new TException(this, "Left hand side of expression must be a boolean value", "yes or no");
                TBoolean bBool = b as TBoolean;
                if (bBool == null)
                    return new TException(this, "Right hand side of expression must be a boolean value", "yes or no");

                group[index - 1] = new TBoolean(aBool.Value && bBool.Value);
                group.RemoveRange(index, 2);
            }

            while ((index = group.IndexOf("or")) >= 0)
            {
                if ((index - 1 < 0) || (index + 1 >= group.Count))
                    return new TException(this, "Invalid expression term ','");

                TType a = TType.Parse(this, group[index - 1]);
                if (a is TException) return a as TException;
                TType b = TType.Parse(this, group[index + 1]);
                if (b is TException) return b as TException;

                TBoolean aBool = a as TBoolean;
                if (aBool == null)
                    return new TException(this, "Left hand side of expression must be a boolean value", "yes or no");
                TBoolean bBool = b as TBoolean;
                if (bBool == null)
                    return new TException(this, "Right hand side of expression must be a boolean value", "yes or no");

                group[index - 1] = new TBoolean(aBool.Value || bBool.Value);
                group.RemoveRange(index, 2);
            }

            return null;
        }