public static void TestStringConcatenation()
        {
            var calculator = new Python3Calculator();
            var l = new Literal("Hello ");
            var r = new Literal("World!");
            var intNumber = new Literal(3);
            var floatNumber = new Literal(3.0f);

            AssertEquals(calculator.Add(l, r).AsValue(), "Hello World!");
            AssertEquals(calculator.Add(r, l).AsValue(), "World!Hello ");

            AssertException<InvalidOperationException>(() => calculator.Add(l, intNumber));
            AssertException<InvalidOperationException>(() => calculator.Add(r, floatNumber));
            AssertException<InvalidOperationException>(() => calculator.Add(intNumber, l));
            AssertException<InvalidOperationException>(() => calculator.Add(floatNumber, r));

            AssertException<InvalidOperationException>(() => calculator.Subtract(l, r));
            AssertException<InvalidOperationException>(() => calculator.Subtract(l, intNumber));
            AssertException<InvalidOperationException>(() => calculator.Subtract(r, floatNumber));
            AssertException<InvalidOperationException>(() => calculator.Subtract(intNumber, l));
            AssertException<InvalidOperationException>(() => calculator.Subtract(floatNumber, r));

            AssertException<InvalidOperationException>(() => calculator.Multiply(l, r));
            AssertException<InvalidOperationException>(() => calculator.Multiply(l, intNumber));
            AssertException<InvalidOperationException>(() => calculator.Multiply(r, floatNumber));
            AssertException<InvalidOperationException>(() => calculator.Multiply(intNumber, l));
            AssertException<InvalidOperationException>(() => calculator.Multiply(floatNumber, r));

            AssertException<InvalidOperationException>(() => calculator.Divide(l, r));
            AssertException<InvalidOperationException>(() => calculator.Divide(l, intNumber));
            AssertException<InvalidOperationException>(() => calculator.Divide(r, floatNumber));
            AssertException<InvalidOperationException>(() => calculator.Divide(intNumber, l));
            AssertException<InvalidOperationException>(() => calculator.Divide(floatNumber, r));
        }
        public static void TestIntArithmetic()
        {
            var calculator = new Python3Calculator();
            var l = new Literal(3);
            var r = new Literal(5);
            var zero = new Literal(0);

            AssertEquals(calculator.Add(l, l).AsValue(), 6);
            AssertEquals(calculator.Add(l, r).AsValue(), 8);
            AssertEquals(calculator.Add(r, l).AsValue(), 8);
            AssertEquals(calculator.Add(r, r).AsValue(), 10);
            AssertEquals(calculator.Add(l, zero).AsValue(), 3);
            AssertEquals(calculator.Add(r, zero).AsValue(), 5);

            AssertEquals(calculator.Subtract(l, l).AsValue(), 0);
            AssertEquals(calculator.Subtract(l, r).AsValue(), -2);
            AssertEquals(calculator.Subtract(r, l).AsValue(), 2);
            AssertEquals(calculator.Subtract(r, r).AsValue(), 0);
            AssertEquals(calculator.Subtract(l, zero).AsValue(), 3);
            AssertEquals(calculator.Subtract(r, zero).AsValue(), 5);

            AssertEquals(calculator.Multiply(l, l).AsValue(), 9);
            AssertEquals(calculator.Multiply(l, r).AsValue(), 15);
            AssertEquals(calculator.Multiply(r, l).AsValue(), 15);
            AssertEquals(calculator.Multiply(r, r).AsValue(), 25);
            AssertEquals(calculator.Multiply(l, zero).AsValue(), 0);
            AssertEquals(calculator.Multiply(r, zero).AsValue(), 0);

            AssertEquals(calculator.Divide(l, l).AsValue(), 1);
            AssertEquals(calculator.Divide(l, r).AsValue(), 0);
            AssertEquals(calculator.Divide(r, l).AsValue(), 1);
            AssertEquals(calculator.Divide(r, r).AsValue(), 1);

            AssertException<DivideByZeroException>(() => calculator.Divide(l, zero));

            AssertEquals(calculator.Mod(l, r), l);
            AssertEquals(calculator.Mod(r, l).AsValue(), 2);
            AssertException<DivideByZeroException>(() => calculator.Mod(l, zero));
            AssertException<DivideByZeroException>(() => calculator.Mod(r, zero));
        }
        public static void TestIntFloatArithmetic()
        {
            var calculator = new Python3Calculator();
            var l = new Literal(3);
            var r = new Literal(5.0f);
            var zeroInt = new Literal(0);
            var zeroFloat = new Literal(0.0f);

            AssertEquals(calculator.Add(l, r).AsValue(), 8.0f);
            AssertEquals(calculator.Add(r, l).AsValue(), 8.0f);

            AssertEquals(calculator.Subtract(l, r).AsValue(), -2.0f);
            AssertEquals(calculator.Subtract(r, l).AsValue(), 2.0f);

            AssertEquals(calculator.Multiply(l, r).AsValue(), 15.0f);
            AssertEquals(calculator.Multiply(r, l).AsValue(), 15.0f);

            AssertEquals(calculator.Divide(l, r).AsValue(), 3 / 5.0f);
            AssertEquals(calculator.Divide(r, l).AsValue(), 5.0f / 3);

            AssertException<DivideByZeroException>(() => calculator.Divide(l, zeroFloat));
            AssertException<DivideByZeroException>(() => calculator.Divide(r, zeroInt));

            AssertEquals(calculator.Mod(l, r).AsValue(), 3.0f);
            AssertEquals(calculator.Mod(r, l).AsValue(), 2.0f);
            AssertException<DivideByZeroException>(() => calculator.Mod(l, zeroFloat));
            AssertException<DivideByZeroException>(() => calculator.Mod(r, zeroInt));
        }
        public static void TestBooleanArithmetic()
        {
            var calculator = new Python3Calculator();
            var t = new Literal(true);
            var f = new Literal(false);

            AssertEquals(calculator.Add(t, t).AsValue(), 2);
            AssertEquals(calculator.Add(t, f).AsValue(), 1);
            AssertEquals(calculator.Add(f, t).AsValue(), 1);
            AssertEquals(calculator.Add(f, f).AsValue(), 0);

            AssertEquals(calculator.Subtract(t, t).AsValue(), 0);
            AssertEquals(calculator.Subtract(t, f).AsValue(), 1);
            AssertEquals(calculator.Subtract(f, t).AsValue(), -1);
            AssertEquals(calculator.Subtract(f, f).AsValue(), 0);

            AssertEquals(calculator.Multiply(t, t).AsValue(), 1);
            AssertEquals(calculator.Multiply(t, f).AsValue(), 0);
            AssertEquals(calculator.Multiply(f, t).AsValue(), 0);
            AssertEquals(calculator.Multiply(f, f).AsValue(), 0);

            AssertEquals(calculator.Divide(t, t).AsValue(), 1);
            AssertEquals(calculator.Divide(f, t).AsValue(), 0);

            AssertException<DivideByZeroException>(() => calculator.Divide(f, f));
            AssertException<DivideByZeroException>(() => calculator.Divide(t, f));

            AssertEquals(calculator.Mod(t, t), new Literal(0));
            AssertEquals(calculator.Mod(f, t), f);
            AssertException<DivideByZeroException>(() => calculator.Mod(f, f));
            AssertException<DivideByZeroException>(() => calculator.Mod(t, f));
        }