Files
prog-intro/java/expression/common/Node.java

174 lines
4.5 KiB
Java

package expression.common;
import java.util.function.Function;
/**
* @author Georgiy Korneev (kgeorgiy@kgeorgiy.info)
*/
public abstract class Node<T> {
private Node() {}
public abstract <R> R get(
Const<T, R> con,
Nullary<R> nul,
Unary<Node<T>, R> un,
Binary<Node<T>, R> bin
);
public abstract <R> R cata(
Const<T, R> con,
Nullary<R> nul,
Unary<R, R> un,
Binary<R, R> 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 <T> Node<T> constant(final T value) {
return new Node<>() {
@Override
public <R> R get(
final Const<T, R> con,
final Nullary<R> nul,
final Unary<Node<T>, R> un,
final Binary<Node<T>, R> bin
) {
return con.apply(value);
}
@Override
public <R> R cata(
final Const<T, R> con,
final Nullary<R> nul,
final Unary<R, R> un,
final Binary<R, R> bin
) {
return con.apply(value);
}
};
}
public static <T> Node<T> op(final String name) {
return new Node<>() {
@Override
public <R> R get(
final Const<T, R> con,
final Nullary<R> nul,
final Unary<Node<T>, R> un,
final Binary<Node<T>, R> bin
) {
return nul.apply(name);
}
@Override
public <R> R cata(
final Const<T, R> con,
final Nullary<R> nul,
final Unary<R, R> un,
final Binary<R, R> bin
) {
return nul.apply(name);
}
};
}
public static <T> Node<T> op(
final String name,
final int priority,
final Node<T> arg
) {
return new Node<>() {
@Override
public <R> R get(
final Const<T, R> con,
final Nullary<R> nul,
final Unary<Node<T>, R> un,
final Binary<Node<T>, R> bin
) {
return un.apply(name, priority, arg);
}
@Override
public <R> R cata(
final Const<T, R> con,
final Nullary<R> nul,
final Unary<R, R> un,
final Binary<R, R> bin
) {
return un.apply(name, priority, arg.cata(con, nul, un, bin));
}
};
}
public static <T> Node<T> op(
final String name,
final Node<T> arg1,
final Node<T> arg2
) {
return new Node<>() {
@Override
public <R> R get(
final Const<T, R> con,
final Nullary<R> nul,
final Unary<Node<T>, R> un,
final Binary<Node<T>, R> bin
) {
return bin.apply(name, arg1, arg2);
}
@Override
public <R> R cata(
final Const<T, R> con,
final Nullary<R> nul,
final Unary<R, R> un,
final Binary<R, R> bin
) {
return bin.apply(
name,
arg1.cata(con, nul, un, bin),
arg2.cata(con, nul, un, bin)
);
}
};
}
@FunctionalInterface
public interface Const<T, R> extends Function<T, R> {}
@FunctionalInterface
public interface Nullary<R> extends Function<String, R> {}
@FunctionalInterface
public interface Unary<T, R> {
R apply(String name, int priority, T arg);
}
@FunctionalInterface
public interface Binary<T, R> {
R apply(String name, T arg1, T arg2);
}
}