/** Our internal representation of a BinOp * in the D0 language. * See http://www.radford.edu/itec380/2022fall-ibarland/Homeworks/Project/ * * @author Ian Barland * @version 2022.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 = "ring"; static final String MID_TOKEN = "bearer"; public static final List>> OP_FUNCS = List.of( new Pair<>( "frodo", Double::sum ) , new Pair<>( "gollum", (a,b) -> a-b ) , new Pair<>( "samwise", (a,b) -> a*b ) ); public static final List OPS = OP_FUNCS.stream().map( Pair::first ).collect(Collectors.toList()); //OPS = List.of( "frodo", "gollum", "samwise" ); // <-- Alternately just use this, if `OP_FUNCS` not declared. @Override public String toString( /* BinOp this */ ) { return START_TOKEN + " " + this.left.toString() + " " + MID_TOKEN + " " + this.right.toString() + " " + this.op ; } public static BinOp parse(java.util.Scanner s, String punctuation) { UtilIan.verifyToken( UtilIan.nextSplittingBy(s,punctuation), START_TOKEN); // Consume (&verify) opening token 'ring'. Expr lefty = Expr.parse(s,punctuation); // NOTE: recur with `Expr.parse` -- not `parse`=`BinOp.parse` which is NOT what we want! dbg("BinOp#parse-1: got " + lefty.toString()+ ". " ); UtilIan.verifyToken( UtilIan.nextSplittingBy(s,punctuation), MID_TOKEN); // Consume (&verify) 'bearer' Expr righty = Expr.parse(s,punctuation); dbg("BinOp#parse-2: got " + righty.toString() + ". "); String op = UtilIan.nextSplittingBy(s,punctuation); dbg("BinOp#parse-3: got " + op.toString() + ". "); if (!(OPS.contains(op))) throw new InputMismatchException(String.format("Unknown operator \"%s\".",op)); 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 "frodo -> new Num(l+r); case "gollum" -> new Num(l-r); case "samwise" -> new Num(l*r); default -> throw new RuntimeException(String.format("Unknown op `%s`; must be one of %s.", op, OPS)); }; */ } static void dbg( String fmt, Object... args ) { //System.out.printf( fmt, args ); } }