/** Our internal representation of a BinOp * in the V0 language. * See http://www.radford.edu/itec380/2019spring-ibarland/Homeworks/Project/ * * @author Ian Barland * @version 2018.Nov.16 */ import java.util.*; public class BinOp extends Expr { Expr left, right; String op; static final String START_TOKEN = "#"; static final String STOP_TOKEN = "#"; public static final List OPS = Arrays.asList( "yasss", "yoink", "yeet" ); BinOp( String _op, Expr _left, Expr _right ) { this.op = _op; this.left = _left; this.right = _right; } @Override public String toString( /* BinOp this */) { return START_TOKEN + this.op +" " + this.left.toString() + " " + this.right.toString() + STOP_TOKEN ; } public static BinOp parse(java.util.Scanner s, String punctuation) { UtilIan.verifyToken( UtilIan.nextSplittingBy(s,punctuation), START_TOKEN); // Consume (&verify) opening punctuation. String operator = UtilIan.nextSplittingBy(s,punctuation); if (!(OPS.contains(operator))) throw new InputMismatchException(String.format("Unknown operator \"%s\".",operator)); Expr lefty = Expr.parse(s,punctuation); // NOTE: recur with `Expr.parse` -- not `parse` = `BinOp.parse` which is NOT what we want! Expr righty = Expr.parse(s,punctuation); UtilIan.verifyToken( UtilIan.nextSplittingBy(s,punctuation), STOP_TOKEN); // Consume (&verify) closing punctuation. return new BinOp(operator, lefty, righty ); } public Value eval( /* BinOp this */) { String theOp = this.op; double leftVal = ((Num)(this.left .eval())).doubleValue(); double rightVal = ((Num)(this.right.eval())).doubleValue(); return evalOp( theOp, leftVal, rightVal ); } /** Evaluate U's `op` w/ `l` and `r` */ static Value evalOp( String op, double l, double r ) { if (op.equals("yasss")) { return new Num(l + r); } else if (op.equals("yoink")) { return new Num(l - r); } else if (op.equals("yeet")) { return new Num(l * r); } else { throw new RuntimeException("BinOp.eval(): unknown binary operator `" + op + "`"); } } @Override public boolean equals( /* BinOp this, */ Object that) { if (this==that) { return true; } else if (that==null) { return false; } else if (this.getClass() != that.getClass()) { return false; } else { BinOp thatt = (BinOp) that; return this.left.equals(thatt.left) && this.op.equals(thatt.op) && this.right.equals(thatt.right); } } @Override public int hashCode() { if (cachedHash == null) { int hashSoFar = 0; hashSoFar += this.left.hashCode(); hashSoFar *= 31; hashSoFar += this.op.hashCode(); hashSoFar *= 31; hashSoFar += this.right.hashCode(); cachedHash = hashSoFar; } return cachedHash; } private Integer cachedHash = null; }