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); } }