package expression; import base.Asserts; import base.ExtendedRandom; import base.Pair; import base.TestCounter; import expression.common.ExpressionKind; import expression.common.Type; import java.util.List; /** * One-argument arithmetic expression over integers. * * @author Georgiy Korneev (kgeorgiy@kgeorgiy.info) */ @FunctionalInterface @SuppressWarnings("ClassReferencesSubclass") public interface Expression extends ToMiniString { int evaluate(int x); // Tests follow. You may temporarily remove everything til the end. Subtract EXAMPLE = new Subtract( new Multiply(new Const(2), new Variable("x")), new Const(3) ); Type TYPE = new Type<>(a -> a, ExtendedRandom::nextInt, int.class); ExpressionKind KIND = new ExpressionKind<>( TYPE, Expression.class, List.of(Pair.of("x", new Variable("x"))), (expr, variables, values) -> expr.evaluate(values.get(0)) ); private static Const c(final int c) { return new Const(c); } @SuppressWarnings({"PointlessArithmeticExpression", "Convert2MethodRef"}) static ExpressionTester tester(final TestCounter counter) { Asserts.assertEquals("Example toString()", "((2 * x) - 3)", EXAMPLE.toString()); Asserts.assertEquals("Example at 5", 7, EXAMPLE.evaluate(5)); Asserts.assertTrue("Example equals 1", new Multiply(new Const(2), new Variable("x")) .equals(new Multiply(new Const(2), new Variable("x")))); Asserts.assertTrue("Example equals 2", !new Multiply(new Const(2), new Variable("x")) .equals(new Multiply(new Variable("x"), new Const(2)))); final Variable vx = new Variable("x"); final Const c1 = c(1); final Const c2 = c(2); return new ExpressionTester<>( counter, KIND, c -> x -> c, (op, a, b) -> x -> op.apply(a.evaluate(x), b.evaluate(x)), (a, b) -> a + b, (a, b) -> a - b, (a, b) -> a * b, (a, b) -> a / b ) .basic("10", "10", x -> 10, c(10)) .basic("x", "x", x -> x, vx) .basic("(x + 2)", "x + 2", x -> x + 2, new Add(vx, c(2))) .basic("(2 - x)", "2 - x", x -> 2 - x, new Subtract(c(2), vx)) .basic("(3 * x)", "3 * x", x -> 3*x, new Multiply(c(3), vx)) .basic("(x + x)", "x + x", x -> x + x, new Add(vx, vx)) .basic("(x / -2)", "x / -2", x -> -x / 2, new Divide(vx, c(-2))) .basic("(2 + x)", "2 + x", x -> 2 + x, new Add(c(2), vx)) .basic("((1 + 2) + 3)", "1 + 2 + 3", x -> 6, new Add(new Add(c(1), c(2)), c(3))) .basic("(1 + (2 + 3))", "1 + 2 + 3", x -> 6, new Add(c(1), new Add(c(2), c(3)))) .basic("((1 - 2) - 3)", "1 - 2 - 3", x -> -4, new Subtract(new Subtract(c(1), c(2)), c(3))) .basic("(1 - (2 - 3))", "1 - (2 - 3)", x -> 2, new Subtract(c(1), new Subtract(c(2), c(3)))) .basic("((1 * 2) * 3)", "1 * 2 * 3", x -> 6, new Multiply(new Multiply(c(1), c(2)), c(3))) .basic("(1 * (2 * 3))", "1 * 2 * 3", x -> 6, new Multiply(c(1), new Multiply(c(2), c(3)))) .basic("((10 / 2) / 3)", "10 / 2 / 3", x -> 10 / 2 / 3, new Divide(new Divide(c(10), c(2)), c(3))) .basic("(10 / (3 / 2))", "10 / (3 / 2)", x -> 10 / (3 / 2), new Divide(c(10), new Divide(c(3), c(2)))) .basic("(10 * (3 / 2))", "10 * (3 / 2)", x -> 10 * (3 / 2), new Multiply(c(10), new Divide(c(3), c(2)))) .basic("(10 + (3 - 2))", "10 + 3 - 2", x -> 10 + (3 - 2), new Add(c(10), new Subtract(c(3), c(2)))) .basic("((x * x) + ((x - 1) / 10))", "x * x + (x - 1) / 10", x -> x * x + (x - 1) / 10, new Add( new Multiply(vx, vx), new Divide(new Subtract(vx, c(1)), c(10)) )) .basic("(x * -1000000000)", "x * -1000000000", x -> x * -1_000_000_000, new Multiply(vx, c(-1_000_000_000))) .basic("(10 / x)", "10 / x", x -> 10 / x, new Divide(c(10), vx)) .basic("(x / x)", "x / x", x -> x / x, new Divide(vx, vx)) .advanced("(2 + 1)", "2 + 1", x -> 2 + 1, new Add(c2, c1)) .advanced("(x - 1)", "x - 1", x -> x - 1, new Subtract(vx, c1)) .advanced("(1 * 2)", "1 * 2", x -> 1 * 2, new Multiply(c1, c2)) .advanced("(x / 1)", "x / 1", x -> x / 1, new Divide(vx, c1)) .advanced("(1 + (2 + 1))", "1 + 2 + 1", x -> 1 + 2 + 1, new Add(c1, new Add(c2, c1))) .advanced("(x - (x - 1))", "x - (x - 1)", x -> x - (x - 1), new Subtract(vx, new Subtract(vx, c1))) .advanced("(2 * (x / 1))", "2 * (x / 1)", x -> 2 * (x / 1), new Multiply(c2, new Divide(vx, c1))) .advanced("(2 / (x - 1))", "2 / (x - 1)", x -> 2 / (x - 1), new Divide(c2, new Subtract(vx, c1))) .advanced("((1 * 2) + x)", "1 * 2 + x", x -> 1 * 2 + x, new Add(new Multiply(c1, c2), vx)) .advanced("((x - 1) - 2)", "x - 1 - 2", x -> x - 1 - 2, new Subtract(new Subtract(vx, c1), c2)) .advanced("((x / 1) * 2)", "x / 1 * 2", x -> x / 1 * 2, new Multiply(new Divide(vx, c1), c2)) .advanced("((2 + 1) / 1)", "(2 + 1) / 1", x -> (2 + 1) / 1, new Divide(new Add(c2, c1), c1)) .advanced("(1 + (1 + (2 + 1)))", "1 + 1 + 2 + 1", x -> 1 + 1 + 2 + 1, new Add(c1, new Add(c1, new Add(c2, c1)))) .advanced("(x - ((1 * 2) + x))", "x - (1 * 2 + x)", x -> x - (1 * 2 + x), new Subtract(vx, new Add(new Multiply(c1, c2), vx))) .advanced("(x * (2 / (x - 1)))", "x * (2 / (x - 1))", x -> x * (2 / (x - 1)), new Multiply(vx, new Divide(c2, new Subtract(vx, c1)))) .advanced("(x / (1 + (2 + 1)))", "x / (1 + 2 + 1)", x -> x / (1 + 2 + 1), new Divide(vx, new Add(c1, new Add(c2, c1)))) .advanced("((1 * 2) + (2 + 1))", "1 * 2 + 2 + 1", x -> 1 * 2 + 2 + 1, new Add(new Multiply(c1, c2), new Add(c2, c1))) .advanced("((2 + 1) - (2 + 1))", "2 + 1 - (2 + 1)", x -> 2 + 1 - (2 + 1), new Subtract(new Add(c2, c1), new Add(c2, c1))) .advanced("((x - 1) * (x / 1))", "(x - 1) * (x / 1)", x -> (x - 1) * (x / 1), new Multiply(new Subtract(vx, c1), new Divide(vx, c1))) .advanced("((x - 1) / (1 * 2))", "(x - 1) / (1 * 2)", x -> (x - 1) / (1 * 2), new Divide(new Subtract(vx, c1), new Multiply(c1, c2))) .advanced("(((x - 1) - 2) + x)", "x - 1 - 2 + x", x -> x - 1 - 2 + x, new Add(new Subtract(new Subtract(vx, c1), c2), vx)) .advanced("(((1 * 2) + x) - 1)", "1 * 2 + x - 1", x -> 1 * 2 + x - 1, new Subtract(new Add(new Multiply(c1, c2), vx), c1)) .advanced("(((2 + 1) / 1) * x)", "(2 + 1) / 1 * x", x -> (2 + 1) / 1 * x, new Multiply(new Divide(new Add(c2, c1), c1), vx)) .advanced("((2 / (x - 1)) / 2)", "2 / (x - 1) / 2", x -> 2 / (x - 1) / 2, new Divide(new Divide(c2, new Subtract(vx, c1)), c2)); } }