internal static Tuple <OperandType> DoUnaryCastOperation(DoubleOperandFunctionMatrix matrix, Stack <IOperand> operandStack, IBackingStore backingStore, Operand castTo)
        {
            IOperand operand = PopAndResolve(operandStack, backingStore);

            IOperand result = matrix.PerformDelegate(operand, castTo);

            if (result != null)
            {
                operandStack.Push(result);
                return(null);
            }
            else
            {
                // Signal an error ...
                return(new Tuple <OperandType>(operand.Type));
            }
        }
        internal static Tuple <OperandType, OperandType> DoOperation(DoubleOperandFunctionMatrix matrix, Stack <IOperand> stack, IBackingStore backingStore)
        {
            IOperand second = PopAndResolve(stack, backingStore);
            IOperand first  = PopAndResolve(stack, backingStore);

            IOperand result = matrix.PerformDelegate(first, second);

            if (result != null)
            {
                stack.Push(result);
                return(null);
            }
            else
            {
                // Signal an error ...
                return(new Tuple <OperandType, OperandType>(first.Type, second.Type));
            }
        }
        /// <summary>
        /// This ought to be implemented with a FunctionMartix but it would be huge.
        /// This way is easier!
        /// </summary>
        internal static Tuple <OperandType, OperandType> DoSetEquals(DoubleOperandFunctionMatrix matrix, Stack <IOperand> stack, IBackingStore backingStore, long parserPosition)
        {
            IOperand second = PopAndResolve(stack, backingStore);
            IOperand first  = stack.Pop();      // Not PopAndResolve. LHS must be a variable.

            if (first.Type != OperandType.Variable)
            {
                throw new ExpressionEvaluatorException(parserPosition, ExpressionEvaluatorException.ExceptionCause.BadOperand, "LHS of '=' is a '" + first.Type + "' when it must be a variable");
            }
            else
            {
                string varName = (string)first.GetValue();

                (OperandType type, object value)valueAndType;
                try
                {
                    // We need the type, don't need the value because it's going to be overwritten.
                    valueAndType = backingStore.GetValue(varName);
                }
                catch (Exception ex)
                {
                    throw new ExpressionEvaluatorException(-1, ExpressionEvaluatorException.ExceptionCause.UndefinedVariable, $"'{varName}'");
                }

                // type is needed so we can pick out the correct martrix operation. Value is irrelevant as it is overwritten.
                var firstOperand = new Operand(first.ParserPosition, valueAndType.type, valueAndType.value);

                IOperand result = matrix.PerformDelegate(firstOperand, second);

                if (result != null)
                {
                    backingStore.SetValue(varName, result.GetValue());
                    stack.Push(result);
                    return(null);
                }
                else
                {
                    // Signal an error ...
                    return(new Tuple <OperandType, OperandType>(first.Type, second.Type));
                }
            }
        }