/** Operaciones sobre expresiones, cada una en un solo switch exhaustivo. */
public final class Calc {
    private Calc() {
    }

    public static int eval(Expr e) {
        return switch (e) {
            case Num(int v) -> v;
            case Add(Expr l, Expr r) -> eval(l) + eval(r);
            case Mul(Expr l, Expr r) -> eval(l) * eval(r);
        };
    }

    /** Texto de la expresión; las sumas van entre paréntesis. */
    public static String show(Expr e) {
        return switch (e) {
            case Num(int v) -> Integer.toString(v);
            case Add(Expr l, Expr r) -> "(" + show(l) + " + " + show(r) + ")";
            case Mul(Expr l, Expr r) -> show(l) + " * " + show(r);
        };
    }

    /** Quita los 1 que multiplican y los 0 que suman. Patrones anidados con guards. */
    public static Expr simplify(Expr e) {
        return switch (e) {
            case Mul(Num(int v), Expr r) when v == 1 -> simplify(r);
            case Mul(Expr l, Num(int v)) when v == 1 -> simplify(l);
            case Add(Num(int v), Expr r) when v == 0 -> simplify(r);
            case Add(Expr l, Num(int v)) when v == 0 -> simplify(l);
            case Add(Expr l, Expr r) -> new Add(simplify(l), simplify(r));
            case Mul(Expr l, Expr r) -> new Mul(simplify(l), simplify(r));
            case Num n -> n;
        };
    }
}
