/** Our internal representation of a BinOp * in the Z0 language. * See http://www.radford.edu/itec380/2021spring-ibarland/Homeworks/Project/ * * @author Ian Barland * @version 2021.Apr.05 */ import java.util.*; import java.util.function.*; import java.util.stream.*; public record BinOp( String op, Expr left, Expr right) implements Expr { static final String START_TOKEN = "["; static final String STOP_TOKEN = "]"; public static final List>> OP_FUNCS = List.of( new Pair<>( "add", Double::sum ) , new Pair<>( "sub", (a,b) -> a-b ) , new Pair<>( "mul", (a,b) -> a*b ) ); public static final List OPS = OP_FUNCS.stream().map( Pair::first ).collect(Collectors.toList()); //OPS = List.of( "add", "sub", "mul" ); // <-- Alternately just use this, if `OP_FUNCS` not declared. @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 op = UtilIan.nextSplittingBy(s,punctuation); if (!(OPS.contains(op))) throw new InputMismatchException(String.format("Unknown operator \"%s\".",op)); Expr lefty = Expr.parse(s,punctuation); Expr righty = Expr.parse(s,punctuation); // NOTE: recur with `Expr.parse` -- not `parse`=`BinOp.parse` which is NOT what we want! UtilIan.verifyToken( UtilIan.nextSplittingBy(s,punctuation), STOP_TOKEN); // Consume (&verify) closing punctuation. return new BinOp(op, 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 evalBinOp( theOp, leftVal, rightVal ); } /** Evaluate Z's `op` w/ `l` and `r` */ static Value evalBinOp( String op, double l, double r ) { Pair> opFunc = OP_FUNCS.stream() // didn't declare OP_FUNCS? See comment below. .filter(pr -> pr.first().equals(op) ) .findFirst() .orElseThrow( () -> new InputMismatchException(String.format("Unknown op `%s`; must be one of %s.", op, OPS)) ); return new Num( opFunc.second().apply(l,r) ); /* If OP_FUNCS wasn't defined, delete the above two statments, and instead use the following: return switch(op) { case "add" -> new Num(l+r); case "sub" -> new Num(l-r); case "mul" -> new Num(l*r); default -> throw new RuntimeException(String.format("Unknown op `%s`; must be one of %s.", op, OPS)); }; */ } }