diff options
| -rw-r--r-- | base/src/bjc/dicelang/Errors.java | 10 | ||||
| -rw-r--r-- | base/src/bjc/dicelang/Parser.java | 1 | ||||
| -rw-r--r-- | base/src/bjc/dicelang/Tokenizer.java | 7 | ||||
| -rw-r--r-- | base/src/bjc/dicelang/eval/DecimalEvaluatorResult.java | 39 | ||||
| -rw-r--r-- | base/src/bjc/dicelang/eval/Evaluator.java | 74 | ||||
| -rw-r--r-- | base/src/bjc/dicelang/eval/EvaluatorResult.java | 4 | ||||
| -rw-r--r-- | base/src/bjc/dicelang/tokens/DecimalToken.java | 40 | ||||
| -rw-r--r-- | base/src/bjc/dicelang/tokens/Token.java | 6 |
8 files changed, 174 insertions, 7 deletions
diff --git a/base/src/bjc/dicelang/Errors.java b/base/src/bjc/dicelang/Errors.java index 10e737f..f36752c 100644 --- a/base/src/bjc/dicelang/Errors.java +++ b/base/src/bjc/dicelang/Errors.java @@ -74,6 +74,10 @@ public class Errors { /* Evaluator Errors */ /** + * Arithmetic error + */ + EK_EVAL_ARITH, + /** * Unknown node type */ EK_EVAL_INVNODE, @@ -350,7 +354,11 @@ public class Errors { case EK_TOK_INVFLEX: System.out.printf("\tERROR: Invalid flexadecimal number %s in base %s\n", args[0], args[1]); break; - + + case EK_EVAL_ARITH: + System.out.printf("\tERROR: Arithmetic error in evaluator: %s\n", args[0]); + break; + case EK_EVAL_INVNODE: System.out.printf("\tERROR: Unknown node in evaluator: %s\n", args[0]); break; diff --git a/base/src/bjc/dicelang/Parser.java b/base/src/bjc/dicelang/Parser.java index 6879c4f..d6d4105 100644 --- a/base/src/bjc/dicelang/Parser.java +++ b/base/src/bjc/dicelang/Parser.java @@ -118,6 +118,7 @@ public class Parser { break; case INT_LIT: + case DEC_LIT: case FLOAT_LIT: case STRING_LIT: case VREF: diff --git a/base/src/bjc/dicelang/Tokenizer.java b/base/src/bjc/dicelang/Tokenizer.java index 7aed861..5ddd82b 100644 --- a/base/src/bjc/dicelang/Tokenizer.java +++ b/base/src/bjc/dicelang/Tokenizer.java @@ -1,9 +1,11 @@ package bjc.dicelang; +import java.math.BigDecimal; import java.util.regex.Matcher; import java.util.regex.Pattern; import bjc.dicelang.dice.DiceBox; +import bjc.dicelang.tokens.DecimalToken; import bjc.dicelang.tokens.DiceToken; import bjc.dicelang.tokens.FloatToken; import bjc.dicelang.tokens.Token; @@ -165,8 +167,11 @@ public class Tokenizer { Errors.inst.printError(EK_TOK_INVFLEX, flexNum, Integer.toString(parseBase)); return Token.NIL_TOKEN; } + } else if (TokenUtils.isSuffixedDouble(token, "f")) { + String unsuffixedToken = token.substring(0, token.length() - 1); + tk = new FloatToken(Double.parseDouble(unsuffixedToken)); } else if (TokenUtils.isDouble(token)) { - tk = new FloatToken(Double.parseDouble(token)); + tk = new DecimalToken(new BigDecimal(token)); } else if (DiceBox.isValidExpression(token)) { tk = new DiceToken(DiceBox.parseExpression(token)); } else { diff --git a/base/src/bjc/dicelang/eval/DecimalEvaluatorResult.java b/base/src/bjc/dicelang/eval/DecimalEvaluatorResult.java new file mode 100644 index 0000000..8b37d53 --- /dev/null +++ b/base/src/bjc/dicelang/eval/DecimalEvaluatorResult.java @@ -0,0 +1,39 @@ +package bjc.dicelang.eval; + +import java.math.BigDecimal; +import java.util.Objects; + +public class DecimalEvaluatorResult extends EvaluatorResult { + public BigDecimal val; + + public DecimalEvaluatorResult(BigDecimal val) { + super(Type.DEC); + + this.val = val; + } + + @Override + public String toString() { + return super.toString() + "(" + val + ")"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + Objects.hash(val); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + DecimalEvaluatorResult other = (DecimalEvaluatorResult) obj; + return Objects.equals(val, other.val); + } +} diff --git a/base/src/bjc/dicelang/eval/Evaluator.java b/base/src/bjc/dicelang/eval/Evaluator.java index 9e41017..3717de3 100644 --- a/base/src/bjc/dicelang/eval/Evaluator.java +++ b/base/src/bjc/dicelang/eval/Evaluator.java @@ -1,5 +1,6 @@ package bjc.dicelang.eval; +import java.math.BigDecimal; import java.util.Deque; import java.util.Iterator; import java.util.LinkedList; @@ -8,6 +9,7 @@ import java.util.function.Consumer; import bjc.dicelang.DiceLangEngine; import bjc.dicelang.Errors; import bjc.dicelang.Node; +import bjc.dicelang.Node.Type; import bjc.dicelang.dice.CompoundDie; import bjc.dicelang.dice.Die; import bjc.dicelang.dice.MathDie; @@ -15,6 +17,7 @@ import bjc.dicelang.dice.ScalarDiceExpression; import bjc.dicelang.dice.ScalarDie; import bjc.dicelang.dice.SimpleDie; import bjc.dicelang.dice.SimpleDieList; +import bjc.dicelang.tokens.DecimalToken; import bjc.dicelang.tokens.DiceToken; import bjc.dicelang.tokens.FloatToken; import bjc.dicelang.tokens.Token; @@ -42,7 +45,7 @@ import static bjc.dicelang.eval.EvaluatorResult.Type.*; public class Evaluator { /* The steps of type coercion. */ private static enum CoerceSteps { - INTEGER, DOUBLE; + INTEGER, DOUBLE, DECIMAL; } /* The context during iteration. */ @@ -254,7 +257,9 @@ public class Evaluator { /* Move up to coercing to a float. */ if (res.type == FLOAT) { curLevel = CoerceSteps.DOUBLE; - } + } else if (res.type == DEC) { + curLevel = CoerceSteps.DECIMAL; + } children.add(nChild); } @@ -272,6 +277,20 @@ public class Evaluator { IntegerEvaluatorResult rs = (IntegerEvaluatorResult) res; nd.resultVal = new FloatEvaluatorResult(rs.value); + } else if (curLevel == CoerceSteps.DECIMAL) { + IntegerEvaluatorResult rs = (IntegerEvaluatorResult) res; + + nd.resultVal = new DecimalEvaluatorResult(new BigDecimal(rs.value)); + } + break; + case FLOAT: + /* + * Coerce decimals to doubles if we need to. + */ + if (curLevel == CoerceSteps.DECIMAL) { + FloatEvaluatorResult rs = (FloatEvaluatorResult) res; + + nd.resultVal = new DecimalEvaluatorResult(new BigDecimal(rs.floatVal)); } default: /* Do nothing */ @@ -462,6 +481,9 @@ public class Evaluator { } else if (left.type == INT && right.type != INT) { Errors.inst.printError(EK_EVAL_MISMATH); return new SimpleTree<>(Node.FAIL(right)); + } else if (left.type == DEC && right.type != DEC) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new SimpleTree<>(Node.FAIL(right)); } else if (left.type == FLOAT && right.type != FLOAT) { Errors.inst.printError(EK_EVAL_MISMATH); return new SimpleTree<>(Node.FAIL(right)); @@ -474,6 +496,9 @@ public class Evaluator { } else if (right.type == FLOAT && left.type != FLOAT) { Errors.inst.printError(EK_EVAL_MISMATH); return new SimpleTree<>(Node.FAIL(left)); + } else if (right.type == DEC && left.type != DEC) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new SimpleTree<>(Node.FAIL(left)); } else if (right.type == DICE && left.type != DICE) { Errors.inst.printError(EK_EVAL_MISMATH); return new SimpleTree<>(Node.FAIL(left)); @@ -488,6 +513,11 @@ public class Evaluator { long rval = ((IntegerEvaluatorResult) right).value; res = new IntegerEvaluatorResult(lval + rval); + } else if (left.type == DEC) { + BigDecimal lval = ((DecimalEvaluatorResult) left).val; + BigDecimal rval = ((DecimalEvaluatorResult) right).val; + + res = new DecimalEvaluatorResult(lval.add(rval)); } else if (left.type == DICE) { if (((DiceEvaluatorResult) left).diceVal.isList()) { Errors.inst.printError(EK_EVAL_INVDICE, left.toString()); @@ -514,6 +544,11 @@ public class Evaluator { long rval = ((IntegerEvaluatorResult) right).value; res = new IntegerEvaluatorResult(lval - rval); + } else if (left.type == DEC) { + BigDecimal lval = ((DecimalEvaluatorResult) left).val; + BigDecimal rval = ((DecimalEvaluatorResult) right).val; + + res = new DecimalEvaluatorResult(lval.subtract(rval)); } else if (left.type == DICE) { if (((DiceEvaluatorResult) left).diceVal.isList()) { Errors.inst.printError(EK_EVAL_INVDICE, left.toString()); @@ -540,6 +575,11 @@ public class Evaluator { long rval = ((IntegerEvaluatorResult) right).value; res = new IntegerEvaluatorResult(lval * rval); + } else if (left.type == DEC) { + BigDecimal lval = ((DecimalEvaluatorResult) left).val; + BigDecimal rval = ((DecimalEvaluatorResult) right).val; + + res = new DecimalEvaluatorResult(lval.multiply(rval)); } else if (left.type == DICE) { if (((DiceEvaluatorResult) left).diceVal.isList()) { Errors.inst.printError(EK_EVAL_INVDICE, left.toString()); @@ -571,6 +611,24 @@ public class Evaluator { } else { res = new FloatEvaluatorResult(lval / rval); } + } else if (left.type == DEC) { + BigDecimal lval = ((DecimalEvaluatorResult) left).val; + BigDecimal rval = ((DecimalEvaluatorResult) right).val; + + if (rval.equals(BigDecimal.ZERO)) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new FailureEvaluatorResult(right); + } + try { + res = new DecimalEvaluatorResult(lval.divide(rval)); + } catch (ArithmeticException aex) { + Errors.inst.printError(EK_EVAL_ARITH, aex.getMessage()); + SimpleTree<Node> cause = new SimpleTree<Node>(new Node(Type.BINOP, op), + new SimpleTree<>(new Node(Type.RESULT, left)), + new SimpleTree<>(new Node(Type.RESULT, right))); + + res = new FailureEvaluatorResult(cause); + } } else if (left.type == FLOAT) { if (((FloatEvaluatorResult) right).floatVal == 0) { Errors.inst.printError(EK_EVAL_DIVZERO); @@ -597,6 +655,15 @@ public class Evaluator { } else { res = new IntegerEvaluatorResult((int) (lval / rval)); } + } else if (left.type == DEC) { + BigDecimal lval = ((DecimalEvaluatorResult) left).val; + BigDecimal rval = ((DecimalEvaluatorResult) right).val; + + if (rval.equals(BigDecimal.ZERO)) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new FailureEvaluatorResult(right); + } + res = new DecimalEvaluatorResult(lval.divideToIntegralValue(rval)); } else if (left.type == FLOAT) { if (((FloatEvaluatorResult) right).floatVal == 0) { Errors.inst.printError(EK_EVAL_DIVZERO); @@ -634,6 +701,9 @@ public class Evaluator { case DICE_LIT: res = new DiceEvaluatorResult(((DiceToken) tk).diceValue); break; + case DEC_LIT: + res = new DecimalEvaluatorResult(((DecimalToken) tk).val); + break; case STRING_LIT: res = new StringEvaluatorResult(eng.getStringLiteral((int) tk.intValue)); break; diff --git a/base/src/bjc/dicelang/eval/EvaluatorResult.java b/base/src/bjc/dicelang/eval/EvaluatorResult.java index ff86447..f721734 100644 --- a/base/src/bjc/dicelang/eval/EvaluatorResult.java +++ b/base/src/bjc/dicelang/eval/EvaluatorResult.java @@ -28,6 +28,10 @@ public class EvaluatorResult { */ INT, /** + * The type of a decimal + */ + DEC, + /** * The type of a float. */ FLOAT, diff --git a/base/src/bjc/dicelang/tokens/DecimalToken.java b/base/src/bjc/dicelang/tokens/DecimalToken.java new file mode 100644 index 0000000..8a7507f --- /dev/null +++ b/base/src/bjc/dicelang/tokens/DecimalToken.java @@ -0,0 +1,40 @@ +package bjc.dicelang.tokens; + +import java.math.BigDecimal; +import java.util.Objects; + +public class DecimalToken extends Token { + public BigDecimal val; + + public DecimalToken(BigDecimal val) { + super(Type.DEC_LIT); + + this.val = val; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + Objects.hash(val); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + DecimalToken other = (DecimalToken) obj; + return Objects.equals(val, other.val); + } + + @Override + public String toString() { + return super.toString() + "(" + val.toString() + ")"; + } + +} diff --git a/base/src/bjc/dicelang/tokens/Token.java b/base/src/bjc/dicelang/tokens/Token.java index e8fc605..863adeb 100644 --- a/base/src/bjc/dicelang/tokens/Token.java +++ b/base/src/bjc/dicelang/tokens/Token.java @@ -10,7 +10,6 @@ import bjc.funcdata.ListEx; /** * Lexer token. */ -@SuppressWarnings("javadoc") public class Token { public final static Token NIL_TOKEN = new Token(Type.NIL); @@ -31,7 +30,7 @@ public class Token { /* * Literal tokens. */ - INT_LIT, FLOAT_LIT, STRING_LIT, VREF, DICE_LIT, + INT_LIT, DEC_LIT, FLOAT_LIT, STRING_LIT, VREF, DICE_LIT, /* * Dice operators. @@ -162,7 +161,8 @@ public class Token { @Override public int hashCode() { - // TODO Auto-generated method stub + // TODO: come up with a better way to implement this + // this is not a compliant hashCode implementation return super.hashCode(); } } |
