001package composite.four;
002import java.util.List;
003import java.util.LinkedList;
004
005public class ExprFactory {
006        private ExprFactory() {}
007        static public Expr newConst(int v) {
008                return new Const(v);
009        }
010        static public Expr newPlus(Expr l, Expr r) {
011                return new BinOp(l, new OpAdd(), r);
012        }
013        static public Expr newMinus(Expr l, Expr r) {
014                return new BinOp(l, new OpSub(), r);
015        }
016        static public Expr newMult(Expr l, Expr r) {
017                return new BinOp(l, new OpMul(), r);
018        }
019        static public Expr newQuot(Expr l, Expr r) {
020                return new BinOp(l, new OpDiv(), r);
021        }
022        static public ExprBuilder newPlusBuilder() {
023                return new NaryOpBuilder(new OpAdd(), new Const(0));
024        }
025        static public ExprBuilder newMultBuilder() {
026                return new NaryOpBuilder(new OpMul(), new Const(1));
027        }
028}
029
030final class Const implements Expr {
031        private final int v;
032        public Const(int v) {
033                this.v = v;
034        }
035        public int eval() {
036                return v;
037        }
038        public String toString() {
039                return Integer.toString(v);
040        }
041}
042
043final class BinOp implements Expr {
044        private final Expr l;
045        private final Expr r;
046        private final Op op;
047        public BinOp(Expr l, Op op, Expr r) {
048                if ((l == null) || (op == null) || (r == null)) {
049                        throw new IllegalArgumentException();
050                }
051                this.op = op;
052                this.l = l;
053                this.r = r;
054        }
055        public int eval() {
056                return op.eval(l.eval(), r.eval());
057        }
058        public String toString() {
059                return l.toString() + " " + r.toString() + " " + op.toString();
060        }
061}
062
063final class NaryOp implements Expr {
064        private final Expr[] args;
065        private final Expr zero;
066        private final Op op;
067        public NaryOp(Expr[] args, Op op, Expr zero) {
068                // Don't need to test these, since the builder checks them.
069                //     if ((args == null) || (op == null) || (zero == null))
070                //       throw new IllegalArgumentException();
071                //     for (int i=0; i<args.length; i++)
072                //       if (args[i] == null)
073                //         throw new IllegalArgumentException();
074                this.op = op;
075                this.args = args;
076                this.zero = zero;
077        }
078        public int eval() {
079                int result = zero.eval();
080                for (int i=0; i<args.length; i++)
081                        result = op.eval(result, args[i].eval());
082                return result;
083        }
084        public String toString() {
085                StringBuilder sb = new StringBuilder();
086                sb.append("[");
087                for (int i=0; i<args.length; i++) {
088                        sb.append(args[i].toString());
089                        if (i+1<args.length)
090                                sb.append(", ");
091                }
092                sb.append("]");
093                sb.append(op.toString());
094                sb.append(" ");
095                return sb.toString();
096        }
097}
098
099final class NaryOpBuilder implements ExprBuilder {
100        private final List<Expr> args;
101        private final Expr zero;
102        private final Op op;
103        public NaryOpBuilder(Op op, Expr zero) {
104                if ((op == null) || (zero == null))
105                        throw new IllegalArgumentException();
106                this.args = new LinkedList<Expr>();
107                this.op = op;
108                this.zero = zero;
109        }
110        public void add(Expr e) {
111                if (e == null)
112                        throw new IllegalArgumentException();
113                args.add(e);
114        }
115        public Expr toExpr() {
116                return new NaryOp(args.toArray(new Expr[0]), op, zero);
117        }
118}
119
120interface Op {
121        public abstract int eval(int x, int y);
122}
123final class OpAdd implements Op {
124        public String toString() { return "+"; }
125        public int eval(int x, int y) { return x+y; }
126}
127final class OpSub implements Op {
128        public String toString() { return "-"; }
129        public int eval(int x, int y) { return x-y; }
130}
131final class OpMul implements Op {
132        public String toString() { return "*"; }
133        public int eval(int x, int y) { return x*y; }
134}
135final class OpDiv implements Op {
136        public String toString() { return "/"; }
137        public int eval(int x, int y) { return x/y; }
138}