diff options
| author | bculkin2442 <bjculkin@mix.wvu.edu> | 2016-03-28 08:47:23 -0400 |
|---|---|---|
| committer | bculkin2442 <bjculkin@mix.wvu.edu> | 2016-03-28 08:47:23 -0400 |
| commit | 62e94ef994a59e87543445bb3c0ce0a37017a70a (patch) | |
| tree | dfa1a488d3929e3f93e2a91669cdaf97c6d707f3 /dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java | |
| parent | 78d9c539e25f16fd15f06c2b2c48c0ad37a21540 (diff) | |
Renamed packages to suit updated project
Diffstat (limited to 'dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java')
| -rw-r--r-- | dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java new file mode 100644 index 0000000..6e9b836 --- /dev/null +++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTExpression.java @@ -0,0 +1,195 @@ +package bjc.dicelang.ast; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.BinaryOperator; + +import org.apache.commons.lang3.StringUtils; + +import bjc.dicelang.ComplexDice; +import bjc.dicelang.CompoundDice; +import bjc.dicelang.IDiceExpression; +import bjc.utils.data.Pair; +import bjc.utils.parserutils.AST; + +/** + * An implementation of {@link IDiceExpression} backed by an AST of + * {@link IDiceASTNode}s + * + * @author ben + * + */ +public class DiceASTExpression implements IDiceExpression { + + /** + * Build the map of operations to use when collapsing the AST + * + * @param env + * The enviroment to evaluate bindings and such against + * @return The operations to use when collapsing the AST + */ + private static + Map<IDiceASTNode, BinaryOperator<Pair<Integer, AST<IDiceASTNode>>>> + buildOperations(Map<String, DiceASTExpression> env) { + Map<IDiceASTNode, BinaryOperator<Pair<Integer, AST<IDiceASTNode>>>> opCollapsers = + new HashMap<>(); + + opCollapsers.put(OperatorDiceNode.ADD, (left, right) -> { + return left.merge((lval, last) -> right.merge((rval, rast) -> { + return new Pair<>(lval + rval, + new AST<>(OperatorDiceNode.ADD, last, rast)); + })); + + }); + opCollapsers.put(OperatorDiceNode.SUBTRACT, (left, right) -> { + return left.merge((lval, last) -> right.merge((rval, rast) -> { + return new Pair<>(lval - rval, + new AST<>(OperatorDiceNode.SUBTRACT, last, rast)); + })); + + }); + opCollapsers.put(OperatorDiceNode.MULTIPLY, (left, right) -> { + return left.merge((lval, last) -> right.merge((rval, rast) -> { + return new Pair<>(lval * rval, + new AST<>(OperatorDiceNode.MULTIPLY, last, rast)); + })); + + }); + opCollapsers.put(OperatorDiceNode.DIVIDE, (left, right) -> { + return left.merge((lval, last) -> right.merge((rval, rast) -> { + return new Pair<>(lval / rval, + new AST<>(OperatorDiceNode.DIVIDE, last, rast)); + })); + }); + + opCollapsers.put(OperatorDiceNode.ASSIGN, (left, right) -> { + return left.merge((lval, last) -> right.merge((rval, rast) -> { + String nam = last.collapse((nod) -> { + return ((VariableDiceNode) nod).getVariable(); + } , (v) -> (lv, rv) -> null, (r) -> r); + + env.put(nam, new DiceASTExpression(rast, env)); + + return new Pair<>(rval, + new AST<>(OperatorDiceNode.ASSIGN, last, rast)); + })); + }); + + opCollapsers.put(OperatorDiceNode.COMPOUND, (left, right) -> { + return left.merge((lval, last) -> right.merge((rval, rast) -> { + int ival = Integer.parseInt( + Integer.toString(lval) + Integer.toString(rval)); + + return new Pair<>(ival, + new AST<>(OperatorDiceNode.COMPOUND, last, rast)); + })); + }); + opCollapsers.put(OperatorDiceNode.GROUP, (left, right) -> { + return left.merge((lval, last) -> right.merge((rval, rast) -> { + + return new Pair<>(new ComplexDice(lval, rval).roll(), + new AST<>(OperatorDiceNode.GROUP, last, rast)); + })); + }); + + return opCollapsers; + } + + /** + * The AST this expression will evaluate + */ + private AST<IDiceASTNode> ast; + + /** + * The enviroment to evaluate bindings and such against + */ + private Map<String, DiceASTExpression> env; + + /** + * Create a new dice expression backed by an AST + * + * @param ast + * The AST backing this expression + * @param env + * The enviroment to evaluate bindings against + */ + public DiceASTExpression(AST<IDiceASTNode> ast, + Map<String, DiceASTExpression> env) { + this.ast = ast; + this.env = env; + } + + /** + * Expand a leaf AST token into a pair for evaluation + * + * @param tokn + * The token to evaluate + * @return A pair consisting of the token's value and the AST it + * represents + */ + private Pair<Integer, AST<IDiceASTNode>> evalLeaf(IDiceASTNode tokn) { + if (tokn instanceof VariableDiceNode) { + String varName = ((VariableDiceNode) tokn).getVariable(); + + if (env.containsKey(varName)) { + return new Pair<>(env.get(varName).roll(), + new AST<>(tokn)); + } else { + // Handle special case for defining variables + return new Pair<>(0, new AST<>(tokn)); + } + } else { + LiteralDiceNode lnod = (LiteralDiceNode) tokn; + String dat = lnod.getData(); + + if (StringUtils.countMatches(dat, 'c') == 1 + && !dat.equalsIgnoreCase("c")) { + String[] strangs = dat.split("c"); + return new Pair<>(new CompoundDice(strangs).roll(), + new AST<>(tokn)); + } else if (StringUtils.countMatches(dat, 'd') == 1 + && !dat.equalsIgnoreCase("d")) { + /* + * Handle dice groups + */ + return new Pair<>(ComplexDice.fromString(dat).roll(), + new AST<>(tokn)); + } else { + return new Pair<>(Integer.parseInt(dat), new AST<>(tokn)); + } + } + } + + /** + * Get the AST bound to this expression + * + * @return the ast + */ + public AST<IDiceASTNode> getAst() { + return ast; + } + + /* + * (non-Javadoc) + * + * @see bjc.utils.dice.IDiceExpression#roll() + */ + @Override + public int roll() { + Map<IDiceASTNode, BinaryOperator<Pair<Integer, AST<IDiceASTNode>>>> operations = + buildOperations(env); + + return ast.collapse(this::evalLeaf, operations::get, + (r) -> r.merge((left, right) -> left)); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return ast.toString(); + } +} |
