package expression.common; import java.util.function.Function; /** * @author Georgiy Korneev (kgeorgiy@kgeorgiy.info) */ public abstract class Node { private Node() { } public abstract R get(Const con, Nullary nul, Unary, R> un, Binary, R> bin); public abstract R cata(Const con, Nullary nul, Unary un, Binary bin); public final String toPolish() { return cata( T::toString, name -> name, (name, priority, a) -> a + " " + name + ":1", (name, a1, a2) -> a1 + " " + a2 + " " + name + ":2" ); } @Override public final String toString() { return cata( T::toString, name -> name, (name, priority, a) -> name.equals("[") ? "[" + a + "]" : (priority & 1) == 1 ? "(" + name + " " + a + ")" : "(" + a + " " + name + ")", (name, a1, a2) -> "(" + a1 + " " + name + " " + a2 + ")" ); } public static Node constant(final T value) { return new Node<>() { @Override public R get(final Const con, final Nullary nul, final Unary, R> un, final Binary, R> bin) { return con.apply(value); } @Override public R cata(final Const con, final Nullary nul, final Unary un, final Binary bin) { return con.apply(value); } }; } public static Node op(final String name) { return new Node<>() { @Override public R get(final Const con, final Nullary nul, final Unary, R> un, final Binary, R> bin) { return nul.apply(name); } @Override public R cata(final Const con, final Nullary nul, final Unary un, final Binary bin) { return nul.apply(name); } }; } public static Node op(final String name, final int priority, final Node arg) { return new Node<>() { @Override public R get(final Const con, final Nullary nul, final Unary, R> un, final Binary, R> bin) { return un.apply(name, priority, arg); } @Override public R cata(final Const con, final Nullary nul, final Unary un, final Binary bin) { return un.apply(name, priority, arg.cata(con, nul, un, bin)); } }; } public static Node op(final String name, final Node arg1, final Node arg2) { return new Node<>() { @Override public R get(final Const con, final Nullary nul, final Unary, R> un, final Binary, R> bin) { return bin.apply(name, arg1, arg2); } @Override public R cata(final Const con, final Nullary nul, final Unary un, final Binary bin) { return bin.apply(name, arg1.cata(con, nul, un, bin), arg2.cata(con, nul, un, bin)); } }; } @FunctionalInterface public interface Const extends Function {} @FunctionalInterface public interface Nullary extends Function {} @FunctionalInterface public interface Unary { R apply(String name, int priority, T arg); } @FunctionalInterface public interface Binary { R apply(String name, T arg1, T arg2); } }