diff --git a/java/expression/common/TestGeneratorBuilder.java b/java/expression/common/TestGeneratorBuilder.java new file mode 100644 index 0000000..2ea7af0 --- /dev/null +++ b/java/expression/common/TestGeneratorBuilder.java @@ -0,0 +1,192 @@ +package expression.common; + +import base.ExtendedRandom; +import base.Functional; +import expression.ToMiniString; +import expression.common.ExpressionKind.Variables; +import java.util.*; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; + +/** + * @author Georgiy Korneev (kgeorgiy@kgeorgiy.info) + */ +public class TestGeneratorBuilder { + + private final ExtendedRandom random; + + private final Generator.Builder generator; + private final NodeRendererBuilder renderer; + + private final List>, Stream>>> basicTests = + new ArrayList<>(); + private final List> consts; + private final boolean verbose; + + public TestGeneratorBuilder( + final ExtendedRandom random, + final Supplier constant, + final List constants, + final boolean verbose + ) { + this.random = random; + this.verbose = verbose; + + generator = Generator.builder(constant, random); + renderer = new NodeRendererBuilder<>(random); + + consts = Functional.map(constants, Node::constant); + basicTests.add(vars -> consts.stream()); + basicTests.add(List::stream); + } + + private Node c() { + return random.randomItem(consts); + } + + private Node v(final List> variables) { + return random.randomItem(variables); + } + + private static Node f( + final String name, + final int priority, + final Node arg + ) { + return Node.op(name, priority, arg); + } + + private static Node f(final String left, final Node arg) { + return Node.op(left, Integer.MAX_VALUE, arg); + } + + private static Node f( + final String name, + final Node arg1, + final Node arg2 + ) { + return Node.op(name, arg1, arg2); + } + + @SafeVarargs + private void basicTests(final Function>, Node>... tests) { + Arrays.stream(tests) + .map(test -> test.andThen(Stream::of)) + .forEachOrdered(basicTests::add); + } + + public void unary(final String name, final int priority) { + generator.add(name, (priority & 1) * 2 - 1); + renderer.unary(name, priority); + + if (verbose) { + basicTests.add(vars -> + Stream.concat(consts.stream(), vars.stream()).map(a -> + f(name, priority, a) + ) + ); + } else { + basicTests( + vars -> f(name, priority, c()), + vars -> f(name, priority, v(vars)) + ); + } + + final Function>, Node> p1 = vars -> + f(name, priority, f(name, priority, f("+", v(vars), c()))); + final Function>, Node> p2 = vars -> + f("*", v(vars), f("*", v(vars), f(name, priority, c()))); + basicTests( + vars -> f(name, priority, f("+", v(vars), v(vars))), + vars -> f(name, priority, f(name, priority, v(vars))), + vars -> + f( + name, + priority, + f("/", f(name, priority, v(vars)), f("+", v(vars), v(vars))) + ), + p1, + p2, + vars -> f("+", p1.apply(vars), p2.apply(vars)) + ); + } + + public void unary(final String left, final String right) { + generator.add(left, 1); + renderer.unary(left, right); + + if (verbose) { + basicTests.add(vars -> + Stream.concat(consts.stream(), vars.stream()).map(a -> + f(left, a) + ) + ); + } else { + basicTests(vars -> f(left, c()), vars -> f(left, v(vars))); + } + + final Function>, Node> p1 = vars -> + f(left, f(left, f("+", v(vars), c()))); + final Function>, Node> p2 = vars -> + f("*", v(vars), f("*", v(vars), f(left, c()))); + basicTests( + vars -> f(left, f("+", v(vars), v(vars))), + vars -> f(left, f(left, v(vars))), + vars -> f(left, f("/", f(left, v(vars)), f("+", v(vars), v(vars)))), + p1, + p2, + vars -> f("+", p1.apply(vars), p2.apply(vars)) + ); + } + + public void binary(final String name, final int priority) { + generator.add(name, 2); + renderer.binary(name, priority); + + if (verbose) { + basicTests.add(vars -> + Stream.concat(consts.stream(), vars.stream().limit(3)).flatMap( + a -> consts.stream().map(b -> f(name, a, b)) + ) + ); + } else { + basicTests( + vars -> f(name, c(), c()), + vars -> f(name, v(vars), c()), + vars -> f(name, c(), v(vars)), + vars -> f(name, v(vars), v(vars)) + ); + } + + final Function>, Node> p1 = vars -> + f(name, f(name, f("+", v(vars), c()), v(vars)), v(vars)); + final Function>, Node> p2 = vars -> + f("*", v(vars), f("*", v(vars), f(name, c(), v(vars)))); + + basicTests( + vars -> f(name, f(name, v(vars), v(vars)), v(vars)), + vars -> f(name, v(vars), f(name, v(vars), v(vars))), + vars -> + f(name, f(name, v(vars), v(vars)), f(name, v(vars), v(vars))), + vars -> + f( + name, + f("-", f(name, v(vars), v(vars)), c()), + f("+", v(vars), v(vars)) + ), + p1, + p2, + vars -> f("+", p1.apply(vars), p2.apply(vars)) + ); + } + + public TestGenerator build( + final Variables variables + ) { + return new TestGenerator<>( + generator.build(variables, basicTests), + renderer.build() + ); + } +} diff --git a/java/expression/common/Type.java b/java/expression/common/Type.java new file mode 100644 index 0000000..eec683b --- /dev/null +++ b/java/expression/common/Type.java @@ -0,0 +1,66 @@ +package expression.common; + +import base.Asserts; +import base.ExtendedRandom; +import expression.Const; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.function.Function; +import java.util.function.IntFunction; + +/** + * @author Georgiy Korneev (kgeorgiy@kgeorgiy.info) + */ +public class Type { + + private final IntFunction fromInt; + private final Function random; + private final Function constant; + + public Type( + final IntFunction fromInt, + final Function random, + final Class type + ) { + this.fromInt = fromInt; + this.random = random; + + try { + final MethodHandle constructor = + MethodHandles.publicLookup().findConstructor( + Const.class, + MethodType.methodType(void.class, type) + ); + constant = c -> { + try { + return (Const) constructor.invoke(c); + } catch (final Throwable e) { + throw Asserts.error( + "Cannot create new Const(%s): %s", + c, + e + ); + } + }; + } catch (final IllegalAccessException | NoSuchMethodException e) { + throw Asserts.error( + "Cannot find constructor Const(%s): %s", + type, + e + ); + } + } + + public Const constant(final C value) { + return constant.apply(value); + } + + public C fromInt(final int value) { + return fromInt.apply(value); + } + + public C randomValue(final ExtendedRandom random) { + return this.random.apply(random); + } +}