public abstract class Expr { abstract Expr eval(); abstract Expr call(String method, Expr[] es); public static void main(String[] s) { Expr e1 = new Call("plus", new Call("mult", new Int(1), new Expr[] {new Int(2)}), new Expr[] {new Int(3)}); System.out.println("Eval " + e1 + " = " + e1.eval()); Expr e2 = new Call("plus", new Int(1), new Expr[] { new Call("mult", new Int(2), new Expr[] {new Int(3)})}); System.out.println("Eval " + e2 + " = " + e2.eval()); } } abstract class Obj extends Expr { Expr eval() { return this; } } class Int extends Obj { int x; Int(int x) { this.x = x; } Expr call(String method, Expr[] es) { if ("plus".equals(method)) { Expr e = es[0].eval(); if (e instanceof Int) { return new Int(x + ((Int) e).x); } } if ("mult".equals(method)) { Expr e = es[0].eval(); if (e instanceof Int) { return new Int(x * ((Int) e).x); } } return null; } public String toString() { return "" + x; } } class Call extends Expr { String method; Expr obj; Expr[] params; Call(String method, Expr obj, Expr[] params) { this.method = method; this.obj = obj; this.params = params; } Expr eval() { Expr[] evals = new Expr[params.length]; for (int i = 0; i < evals.length; i++) { evals[i] = params[i].eval(); } return obj.eval().call(method, evals); } Expr call(String method, Expr[] es) { return null; } public String toString() { String res = obj + "." + method + "("; for (int i = 0; i < params.length - 1; i++) { res += params[i] + ", "; } if (params.length != 0) { res += params[params.length - 1]; } res += ")"; return res; } }