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}