summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base/src/bjc/dicelang/Errors.java10
-rw-r--r--base/src/bjc/dicelang/Parser.java1
-rw-r--r--base/src/bjc/dicelang/Tokenizer.java7
-rw-r--r--base/src/bjc/dicelang/eval/DecimalEvaluatorResult.java39
-rw-r--r--base/src/bjc/dicelang/eval/Evaluator.java74
-rw-r--r--base/src/bjc/dicelang/eval/EvaluatorResult.java4
-rw-r--r--base/src/bjc/dicelang/tokens/DecimalToken.java40
-rw-r--r--base/src/bjc/dicelang/tokens/Token.java6
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();
}
}