public static void TestXor()
        {
            var calculator = new Python3Calculator();

            // Booleans
            var t = new Literal(true);
            var f = new Literal(false);
            AssertEquals(calculator.Xor(f, t), t);
            AssertEquals(calculator.Xor(t, f), t);
            AssertEquals(calculator.Xor(t, t), f);
            AssertEquals(calculator.Xor(f, f), f);

            // Numbers
            var zero = new Literal(0);
            var one = new Literal(1);
            var a = new Literal(3);
            var b = new Literal(4.0f);
            AssertEquals(calculator.Xor(zero, a), a);
            AssertEquals(calculator.Xor(a, zero), a);
            AssertEquals(calculator.Xor(one, a).AsValue(), 2);
            AssertEquals(calculator.Xor(a, one).AsValue(), 2);
            AssertException<InvalidOperationException>(() => calculator.Xor(b, a));
            AssertException<InvalidOperationException>(() => calculator.Xor(a, b));

            // Numbers and Booleans
            AssertEquals(calculator.Xor(f, a), a);
            AssertEquals(calculator.Xor(a, f), a);
            AssertEquals(calculator.Xor(t, a).AsValue(), 2);
            AssertEquals(calculator.Xor(a, t).AsValue(), 2);

            // Strings
            var str = new Literal("");
            AssertException<InvalidOperationException>(() => calculator.Xor(str, t));
            AssertException<InvalidOperationException>(() => calculator.Xor(t, str));
            AssertException<InvalidOperationException>(() => calculator.Xor(str, zero));
            AssertException<InvalidOperationException>(() => calculator.Xor(zero, str));
        }
        public static void TestOr()
        {
            var calculator = new Python3Calculator();

            // Booleans
            var t = new Literal(true);
            var f = new Literal(false);
            AssertEquals(calculator.Or(f, t), t);
            AssertEquals(calculator.Or(t, f), t);
            AssertEquals(calculator.Or(t, t), t);
            AssertEquals(calculator.Or(f, f), f);

            // Numbers
            var zero = new Literal(0);
            var a = new Literal(3);
            var b = new Literal(4.0f);
            AssertEquals(calculator.Or(zero, a), a);
            AssertEquals(calculator.Or(a, zero), a);
            AssertEquals(calculator.Or(b, a), b);
            AssertEquals(calculator.Or(a, b), a);

            // Numbers and Booleans
            AssertEquals(calculator.Or(t, zero), t);
            AssertEquals(calculator.Or(zero, t), t);
            AssertEquals(calculator.Or(f, zero), zero);
            AssertEquals(calculator.Or(zero, f), f);
            AssertEquals(calculator.Or(t, a), t);
            AssertEquals(calculator.Or(a, t), a);
            AssertEquals(calculator.Or(f, a), a);
            AssertEquals(calculator.Or(a, f), a);
            AssertEquals(calculator.Or(t, b), t);
            AssertEquals(calculator.Or(b, t), b);
            AssertEquals(calculator.Or(f, b), b);
            AssertEquals(calculator.Or(b, f), b);

            // Strings
            var empty = new Literal("");
            var str_a = new Literal("a");
            var str_b = new Literal("b");
            AssertEquals(calculator.Or(empty, str_a), str_a);
            AssertEquals(calculator.Or(str_a, empty), str_a);
            AssertEquals(calculator.Or(empty, empty), empty);
            AssertEquals(calculator.Or(str_a, str_b), str_a);
            AssertEquals(calculator.Or(str_b, str_a), str_b);

            // Strings and Booleans
            AssertEquals(calculator.Or(empty, f), f);
            AssertEquals(calculator.Or(f, empty), empty);
            AssertEquals(calculator.Or(empty, t), t);
            AssertEquals(calculator.Or(t, empty), t);
            AssertEquals(calculator.Or(str_a, f), str_a);
            AssertEquals(calculator.Or(f, str_a), str_a);
            AssertEquals(calculator.Or(str_a, t), str_a);
            AssertEquals(calculator.Or(t, str_a), t);

            // Strings and Numbers
            AssertEquals(calculator.Or(empty, zero), zero);
            AssertEquals(calculator.Or(zero, empty), empty);
            AssertEquals(calculator.Or(empty, a), a);
            AssertEquals(calculator.Or(a, empty), a);
            AssertEquals(calculator.Or(empty, b), b);
            AssertEquals(calculator.Or(b, empty), b);
            AssertEquals(calculator.Or(str_a, zero), str_a);
            AssertEquals(calculator.Or(zero, str_a), str_a);
            AssertEquals(calculator.Or(str_a, a), str_a);
            AssertEquals(calculator.Or(a, str_a), a);
            AssertEquals(calculator.Or(str_a, b), str_a);
            AssertEquals(calculator.Or(b, str_a), b);
        }
        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 TestNot()
        {
            var calculator = new Python3Calculator();

            // Booleans
            var t = new Literal(true);
            var f = new Literal(false);
            AssertEquals(calculator.Not(t).AsValue(), false);
            AssertEquals(calculator.Not(f).AsValue(), true);

            // Numbers
            var zero = new Literal(0);
            var a = new Literal(1);
            var b = new Literal(3);
            AssertEquals(calculator.Not(zero).AsValue(), true);
            AssertEquals(calculator.Not(a).AsValue(), false);
            AssertEquals(calculator.Not(b).AsValue(), false);

            // String
            var empty = new Literal("");
            var str_a = new Literal("a");
            AssertEquals(calculator.Not(empty).AsValue(), true);
            AssertEquals(calculator.Not(str_a).AsValue(), false);
        }
        public static void TestLessThan()
        {
            var calculator = new Python3Calculator();

            // Booleans
            var t = new Literal(true);
            var f = new Literal(false);
            AssertEquals(calculator.LessThan(f, t).AsValue(), true);
            AssertEquals(calculator.LessThan(t, f).AsValue(), false);

            AssertEquals(calculator.LessThan(t, t).AsValue(), false);

            // Numbers
            var a = new Literal(3);
            var b = new Literal(4);
            var c = new Literal(3.4f);
            var d = new Literal(6.0f);
            AssertEquals(calculator.LessThan(a, b).AsValue(), true);
            AssertEquals(calculator.LessThan(b, a).AsValue(), false);
            AssertEquals(calculator.LessThan(c, d).AsValue(), true);
            AssertEquals(calculator.LessThan(d, c).AsValue(), false);
            AssertEquals(calculator.LessThan(a, c).AsValue(), true);
            AssertEquals(calculator.LessThan(c, a).AsValue(), false);
            AssertEquals(calculator.LessThan(c, b).AsValue(), true);
            AssertEquals(calculator.LessThan(b, c).AsValue(), false);

            AssertEquals(calculator.LessThan(a, a).AsValue(), false);
            AssertEquals(calculator.LessThan(c, c).AsValue(), false);

            // Strings
            var str_A = new Literal("A");
            var str_a = new Literal("a");
            var str_b = new Literal("b");
            var str_aa = new Literal("aa");
            AssertEquals(calculator.LessThan(str_A, str_a).AsValue(), true);
            AssertEquals(calculator.LessThan(str_a, str_A).AsValue(), false);
            AssertEquals(calculator.LessThan(str_a, str_b).AsValue(), true);
            AssertEquals(calculator.LessThan(str_b, str_a).AsValue(), false);
            AssertEquals(calculator.LessThan(str_a, str_aa).AsValue(), true);
            AssertEquals(calculator.LessThan(str_aa, str_a).AsValue(), false);
            AssertEquals(calculator.LessThan(str_aa, str_b).AsValue(), true);
            AssertEquals(calculator.LessThan(str_b, str_aa).AsValue(), false);

            AssertEquals(calculator.LessThan(str_a, str_a).AsValue(), false);

            // Combinations
            AssertException<InvalidOperationException>(() => calculator.LessThan(t, str_a));
            AssertException<InvalidOperationException>(() => calculator.LessThan(str_a, t));
            AssertException<InvalidOperationException>(() => calculator.LessThan(a, str_a));
            AssertException<InvalidOperationException>(() => calculator.LessThan(str_a, a));
            AssertException<InvalidOperationException>(() => calculator.LessThan(c, str_a));
            AssertException<InvalidOperationException>(() => calculator.LessThan(str_a, c));
        }
        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 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 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));
        }