summaryrefslogtreecommitdiff
path: root/dice-lang
diff options
context:
space:
mode:
authorbculkin2442 <bjculkin@mix.wvu.edu>2017-02-26 08:22:59 -0500
committerbculkin2442 <bjculkin@mix.wvu.edu>2017-02-27 03:55:15 -0500
commitb776b8a558a2e27e4551768050f7e34e233326b5 (patch)
tree6f574992a406d65ec3fac24a3b0bc498e9d9243a /dice-lang
parent07d8b9547a654021d8c56021779f4cdaa5f03f1b (diff)
Dice math
Diffstat (limited to 'dice-lang')
-rw-r--r--dice-lang/pom.xml20
-rw-r--r--dice-lang/src/bjc/dicelang/v2/Define.java16
-rw-r--r--dice-lang/src/bjc/dicelang/v2/DiceBox.java176
-rw-r--r--dice-lang/src/bjc/dicelang/v2/DiceLangConsole.java42
-rw-r--r--dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java28
-rw-r--r--dice-lang/src/bjc/dicelang/v2/Errors.java8
-rw-r--r--dice-lang/src/bjc/dicelang/v2/Evaluator.java186
-rw-r--r--dice-lang/src/bjc/dicelang/v2/Shunter.java225
-rw-r--r--dice-lang/src/bjc/dicelang/v2/StreamEngine.java2
9 files changed, 475 insertions, 228 deletions
diff --git a/dice-lang/pom.xml b/dice-lang/pom.xml
index a3a3f6f..86855bf 100644
--- a/dice-lang/pom.xml
+++ b/dice-lang/pom.xml
@@ -19,16 +19,36 @@
<artifactId>exec-maven-plugin</artifactId>
<version>1.5.0</version>
<configuration>
+ <executable>java</executable>
+ <arguments>
+ <argument>-agentlib:jdwp=transport=dt_socket,server=y,suspend=n</argument>
+
+ <argument>-classpath</argument>
+ <classpath/>
+ <argument>bjc.dicelang.v2.DiceLangConsole</argument>
+ </arguments>
<mainClass>bjc.dicelang.v2.DiceLangConsole</mainClass>
</configuration>
</plugin>
</plugins>
</build>
+ <repositories>
+ <repository>
+ <id>jline</id>
+ <name>JLine Project Repository</name>
+ <url>http://jline.sourceforge.net/m2repo</url>
+ </repository>
+ </repositories>
<dependencies>
<dependency>
<groupId>bjc</groupId>
<artifactId>BJC-Utils2</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>jline</groupId>
+ <artifactId>jline</artifactId>
+ <version>0.9.9</version>
+ </dependency>
</dependencies>
</project>
diff --git a/dice-lang/src/bjc/dicelang/v2/Define.java b/dice-lang/src/bjc/dicelang/v2/Define.java
index f87bab6..9a68a98 100644
--- a/dice-lang/src/bjc/dicelang/v2/Define.java
+++ b/dice-lang/src/bjc/dicelang/v2/Define.java
@@ -11,13 +11,11 @@ import java.util.regex.PatternSyntaxException;
import static bjc.dicelang.v2.Errors.ErrorKey.*;
public class Define implements UnaryOperator<String> {
- public static enum Type {
- LINE, TOKEN
- }
+ public static enum Type { LINE, TOKEN }
public static final int MAX_RECURS = 10;
- public final int priority;
+ public final int priority;
public final boolean inError;
private boolean doRecur;
@@ -27,7 +25,7 @@ public class Define implements UnaryOperator<String> {
private Pattern searcher;
private Iterator<String> replacers;
- private String replacer;
+ private String replacer;
public Define(int priorty,
boolean isSub, boolean recur, boolean isCircular,
@@ -42,7 +40,6 @@ public class Define implements UnaryOperator<String> {
} catch (PatternSyntaxException psex) {
Errors.inst.printError(EK_DFN_PREDSYN, psex.getMessage());
inError = true;
-
return;
}
}
@@ -52,7 +49,6 @@ public class Define implements UnaryOperator<String> {
} catch (PatternSyntaxException psex) {
Errors.inst.printError(EK_DFN_SRCSYN, psex.getMessage());
inError = true;
-
return;
}
@@ -93,7 +89,6 @@ public class Define implements UnaryOperator<String> {
do {
strang = doPass(tok);
-
recurCount += 1;
} while(!strang.equals(oldStrang) && recurCount < MAX_RECURS);
@@ -112,19 +107,16 @@ public class Define implements UnaryOperator<String> {
if(subType) {
StringBuffer sb = new StringBuffer();
-
while(searcherMatcher.find()) {
if(replacers == null) {
searcherMatcher.appendReplacement(sb,"");
} else {
String replac = replacers.next();
-
searcherMatcher.appendReplacement(sb, replac);
}
}
-
- searcherMatcher.appendTail(sb);
+ searcherMatcher.appendTail(sb);
return sb.toString();
} else {
return searcherMatcher.replaceAll(replacer);
diff --git a/dice-lang/src/bjc/dicelang/v2/DiceBox.java b/dice-lang/src/bjc/dicelang/v2/DiceBox.java
index 2a32f47..ae0481e 100644
--- a/dice-lang/src/bjc/dicelang/v2/DiceBox.java
+++ b/dice-lang/src/bjc/dicelang/v2/DiceBox.java
@@ -12,7 +12,7 @@ public class DiceBox {
public interface Die {
boolean canOptimize();
- long optimize();
+ long optimize();
long roll();
long rollSingle();
@@ -20,7 +20,7 @@ public class DiceBox {
public interface DieList {
boolean canOptimize();
- long[] optimize();
+ long[] optimize();
long[] roll();
}
@@ -33,13 +33,11 @@ public class DiceBox {
public DieExpression(Die scal) {
isList = false;
-
scalar = scal;
}
public DieExpression(DieList lst) {
isList = true;
-
list = lst;
}
@@ -107,12 +105,16 @@ public class DiceBox {
}
public boolean canOptimize() {
- if(diceSize.canOptimize() && diceSize.optimize() == 1) return numDice.canOptimize();
- else return false;
+ if(diceSize.canOptimize() && (diceSize.optimize() <= 1) {
+ return numDice.canOptimize();
+ } else return false;
}
public long optimize() {
- return numDice.optimize();
+ long optSize = diceSize.optimize();
+
+ if(optSize == 0) return 0;
+ else return numDice.optimize();
}
public long roll() {
@@ -145,7 +147,7 @@ public class DiceBox {
}
public boolean canOptimize() {
- return false;
+ return numDice.canOptimize() && numDice.optimize() == 0;
}
public long optimize() {
@@ -153,9 +155,9 @@ public class DiceBox {
}
public long roll() {
- long nDice = numDice.roll();
-
long res = 0;
+
+ long nDice = numDice.roll();
for(int i = 0; i < nDice; i++) {
res += rollSingle();
@@ -165,16 +167,7 @@ public class DiceBox {
}
public long rollSingle() {
- switch(rng.nextInt(3)) {
- case 0:
- return -1;
- case 1:
- return 0;
- case 2:
- return 1;
- default:
- return 0;
- }
+ return rng.nextInt(3) - 1;
}
public String toString() {
@@ -214,14 +207,14 @@ public class DiceBox {
public static class CompoundingDie implements Die {
private Die source;
-
+
private Predicate<Long> compoundOn;
private String compoundPattern;
public CompoundingDie(Die src, Predicate<Long> compound) {
this(src, compound, null);
}
-
+
public CompoundingDie(Die src, Predicate<Long> compound, String patt) {
source = src;
@@ -230,7 +223,7 @@ public class DiceBox {
}
public boolean canOptimize() {
- return false;
+ return source.canOptimize() && source.optimize() == 0;
}
public long optimize() {
@@ -239,7 +232,6 @@ public class DiceBox {
public long roll() {
long res = source.roll();
-
long oldRes = res;
while(compoundOn.test(oldRes)) {
@@ -253,7 +245,6 @@ public class DiceBox {
public long rollSingle() {
long res = source.rollSingle();
-
long oldRes = res;
while(compoundOn.test(oldRes)) {
@@ -274,6 +265,79 @@ public class DiceBox {
}
}
+ public static class MathDie implements Die {
+ public static enum MathOp {
+ ADD, SUBTRACT, MULTIPLY;
+
+ public String toString() {
+ switch(this) {
+ case ADD:
+ return "+";
+ case SUBTRACT:
+ return "-";
+ case MULTIPLY:
+ return "*";
+ default:
+ return this.name();
+ }
+ }
+ }
+
+ private MathOp type;
+
+ private Die left;
+ private Die right;
+
+ public MathDie(MathOp op, Die lft, Die rght) {
+ type = op;
+
+ left = lft;
+ right = rght;
+ }
+
+ public boolean canOptimize() {
+ return left.canOptimize() && right.canOptimize();
+ }
+
+ private long performOp(long lft, long rght) {
+ switch(type) {
+ case ADD:
+ return lft + rght;
+ case SUBTRACT:
+ return lft - rght;
+ case MULTIPLY:
+ return lft * rght;
+ default:
+ return 0;
+ }
+ }
+
+ public long optimize() {
+ long lft = left.optimize();
+ long rght = right.optimize();
+
+ return performOp(lft, rght);
+ }
+
+ public long roll() {
+ long lft = left.roll();
+ long rght = right.roll();
+
+ return performOp(lft, rght);
+ }
+
+ public long rollSingle() {
+ long lft = left.rollSingle();
+ long rght = right.rollSingle();
+
+ return performOp(lft, rght);
+ }
+
+ public String toString() {
+ return left.toString() + " " + type.toString() + " " + right.toString();
+ }
+ }
+
public static class SimpleDieList implements DieList {
private Die numDice;
private Die size;
@@ -284,7 +348,7 @@ public class DiceBox {
}
public boolean canOptimize() {
- if(size.canOptimize() && size.optimize() == 1) {
+ if(size.canOptimize() && size.optimize() <= 1) {
return numDice.canOptimize();
} else {
return false;
@@ -292,12 +356,13 @@ public class DiceBox {
}
public long[] optimize() {
- long[] ret = new long[(int)numDice.optimize()];
+ int sze = (int)numDice.optimize();
+ long res = size.optimize();
- long optSize = size.optimize();
+ long[] ret = new long[sze];
- for(int i = 0; i < optSize; i++) {
- ret[i] = 1;
+ for(int i = 0; i < sze; i++) {
+ ret[i] = res;
}
return ret;
@@ -335,7 +400,8 @@ public class DiceBox {
this(src, explode, null, penetrate);
}
- public ExplodingDice(Die src, Predicate<Long> explode, String patt, boolean penetrate) {
+ public ExplodingDice(Die src, Predicate<Long> explode, String patt,
+ boolean penetrate) {
source = src;
explodeOn = explode;
explodePattern = patt;
@@ -352,21 +418,18 @@ public class DiceBox {
public long[] roll() {
long res = source.roll();
+ long oldRes = res;
List<Long> resList = new LinkedList<>();
- long oldRes = res;
-
while(explodeOn.test(oldRes)) {
oldRes = source.rollSingle();
if(explodePenetrates) oldRes -= 1;
-
resList.add(oldRes);
}
- long[] newRes = new long[resList.size()+1];
-
+ long[] newRes = new long[resList.size() + 1];
newRes[0] = res;
int i = 1;
@@ -391,14 +454,19 @@ public class DiceBox {
if(!isValidExpression(exp)) return null;
if(scalarDiePattern.matcher(exp).matches()) {
- return new DieExpression(new ScalarDie(Long.parseLong(exp.substring(0, exp.indexOf('s')))));
+ Die scal = new ScalarDie(Long.parseLong(exp.substring(0, exp.indexOf('s'))))
+
+ return new DieExpression(scal);
} else if(simpleDiePattern.matcher(exp).matches()) {
String[] dieParts = exp.split("d");
+ long right = Long.parseLong(dieParts[1]);
if(dieParts[0].equals("")) {
- return new DieExpression(new SimpleDie(1, Long.parseLong(dieParts[1])));
+ Die scal = new SimpleDie(1, right)
+ return new DieExpression(scal);
} else {
- return new DieExpression(new SimpleDie(Long.parseLong(dieParts[0]), Long.parseLong(dieParts[1])));
+ Die scal = new SimpleDie(Long.parseLong(dieParts[0]), right);
+ return new DieExpression(scal);
}
} else if(fudgeDiePattern.matcher(exp).matches()) {
String nDice = exp.substring(0, exp.indexOf('d'));
@@ -417,28 +485,32 @@ public class DiceBox {
DieExpression left = parseExpression(dieParts[0]);
Predicate<Long> right = deriveCond(dieParts[1]);
- return new DieExpression(new CompoundingDie(left.scalar, right, dieParts[1]));
+ Die scal = new CompoundingDie(left.scalar, right, dieParts[1])
+ return new DieExpression(scal);
} else if(explodingDiePattern.matcher(exp).matches()) {
String[] dieParts = exp.split("!");
DieExpression left = parseExpression(dieParts[0]);
Predicate<Long> right = deriveCond(dieParts[1]);
- return new DieExpression(new ExplodingDice(left.scalar, right, dieParts[1], false));
+ DieList lst = new ExplodingDice(left.scalar, right, dieParts[1], false);
+ return new DieExpression(lst);
} else if(penetratingDiePattern.matcher(exp).matches()) {
String[] dieParts = exp.split("p!");
DieExpression left = parseExpression(dieParts[0]);
Predicate<Long> right = deriveCond(dieParts[1]);
- return new DieExpression(new ExplodingDice(left.scalar, right, dieParts[1], true));
+ DieList lst = new ExplodingDice(left.scalar, right, dieParts[1], true);
+ return new DieExpression(lst);
} else if(diceListPattern.matcher(exp).matches()) {
String[] dieParts = exp.split("dl");
DieExpression left = parseExpression(dieParts[0]);
DieExpression right = parseExpression(dieParts[1]);
-
- return new DieExpression(new SimpleDieList(left.scalar, right.scalar));
+
+ DieList lst = new SimpleDieList(left.scalar, right.scalar);
+ return new DieExpression();
}
// @TODO give a specific error message
@@ -500,14 +572,14 @@ public class DiceBox {
long num = Long.parseLong(patt.substring(1));
switch(patt.charAt(0)) {
- case '<':
- return (roll) -> roll < num;
- case '=':
- return (roll) -> roll == num;
- case '>':
- return (roll) -> roll > num;
- default:
- return (roll) -> false;
+ case '<':
+ return (roll) -> roll < num;
+ case '=':
+ return (roll) -> roll == num;
+ case '>':
+ return (roll) -> roll > num;
+ default:
+ return (roll) -> false;
}
}
}
diff --git a/dice-lang/src/bjc/dicelang/v2/DiceLangConsole.java b/dice-lang/src/bjc/dicelang/v2/DiceLangConsole.java
index 863bce5..9d69704 100644
--- a/dice-lang/src/bjc/dicelang/v2/DiceLangConsole.java
+++ b/dice-lang/src/bjc/dicelang/v2/DiceLangConsole.java
@@ -1,11 +1,14 @@
package bjc.dicelang.v2;
+import java.io.IOException;
import java.util.List;
import java.util.LinkedList;
-import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import jline.ConsoleReader;
+import jline.Terminal;
+
import static bjc.dicelang.v2.Errors.ErrorKey.*;
public class DiceLangConsole {
@@ -13,20 +16,35 @@ public class DiceLangConsole {
private DiceLangEngine eng;
+ private ConsoleReader read;
+
public DiceLangConsole(String[] args) {
// @TODO do something with the args
commandNumber = 0;
eng = new DiceLangEngine();
+
+ Terminal.setupTerminal();
}
public void run() {
+ try {
+ read = new ConsoleReader();
+ } catch(IOException ioex) {
+ System.out.println("ERROR: Console init failed");
+ return;
+ }
+
System.out.println("dice-lang v0.2");
- Scanner scn = new Scanner(System.in);
+ String comm = null;
- System.out.printf("(%d) dice-lang> ", commandNumber);
- String comm = scn.nextLine();
+ try {
+ comm = read.readLine(String.format("(%d) dice-lang> ", commandNumber));
+ } catch (IOException ioex) {
+ System.out.println("ERROR: I/O failed");
+ return;
+ }
while(!comm.equals("quit") && !comm.equals("exit")) {
if(comm.startsWith("pragma")) {
@@ -45,11 +63,13 @@ public class DiceLangConsole {
commandNumber += 1;
}
- System.out.printf("(%d) dice-lang> ", commandNumber);
- comm = scn.nextLine();
+ try {
+ comm = read.readLine(String.format("(%d) dice-lang> ", commandNumber));
+ } catch (IOException ioex) {
+ System.out.println("ERROR: I/O failed");
+ return;
+ }
}
-
- scn.close();
}
private boolean handlePragma(String pragma) {
@@ -73,6 +93,9 @@ public class DiceLangConsole {
case "prefix":
System.out.println("\tPrefix mode is now " + eng.togglePrefix());
break;
+ case "stepeval":
+ System.out.println("\tStepeval mode is now" + eng.toggleStepEval());
+ break;
case "define":
return defineMode(pragma.substring(7));
case "help":
@@ -99,6 +122,9 @@ public class DiceLangConsole {
case "prefix":
System.out.println("\tToggle prefix mode. (Reverse token order instead of shunting)");
break;
+ case "stepeval":
+ System.out.println("\tToggle stepeval mode. (Print out evaluation progress)");
+ break;
case "define":
System.out.println("\tAdd a macro rewrite directive.");
System.out.println("\tdefine <priority> <type> <recursion> <guard> <circular> <patterns>...");
diff --git a/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java b/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java
index 1517abd..0798988 100644
--- a/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java
+++ b/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java
@@ -112,7 +112,7 @@ public class DiceLangEngine {
debugMode = true;
postfixMode = false;
prefixMode = false;
- stepEval = true;
+ stepEval = false;
streamEng = new StreamEngine(this);
@@ -160,6 +160,12 @@ public class DiceLangEngine {
return prefixMode;
}
+ public boolean toggleStepEval() {
+ stepEval = !stepEval;
+
+ return stepEval;
+ }
+
/*
* Matches quote-delimited strings
* (like "text" or "text\"text")
@@ -174,8 +180,8 @@ public class DiceLangEngine {
*/
private Pattern quotePattern = Pattern.compile("\"([^\\\"]*(?:\\\"(?:[^\\\"])*)*)\"");
- // Similiar to the above, but using angle brackets instead of quotes and not allowing spaces
- private Pattern nonExpandPattern = Pattern.compile("<([^\\>&&[^\\s]]*(?:\\>(?:[^\\>&&[^\\s]])*)*)>");
+ // Similiar to the above, but using angle brackets instead of quotes
+ private Pattern nonExpandPattern = Pattern.compile("<<([^\\>]*(?:\\>(?:[^\\>])*)*)>>");
public boolean runCommand(String command) {
// Sort the defines if they aren't sorted
@@ -352,7 +358,7 @@ public class DiceLangEngine {
int treeNo = 1;
for(ITree<Node> ast : astForest) {
- System.out.println("\t\tTree " + treeNo + " in forest:\n\t\t " + ast);
+ System.out.println("\t\tTree " + treeNo + " in forest:\n" + ast);
if(stepEval) {
int step = 1;
@@ -362,6 +368,13 @@ public class DiceLangEngine {
System.out.printf("\t\tStep %d: Node is %s", step, nodeStep);
+ if(nodeStep == null) {
+ System.out.println();
+
+ step += 1;
+ continue;
+ }
+
if(nodeStep.getHead().type == Node.Type.RESULT) {
EvaluatorResult res = nodeStep.getHead().resultVal;
@@ -387,7 +400,7 @@ public class DiceLangEngine {
System.out.printf("\t\tEvaluates to %s", res);
if(res.type == EvaluatorResult.Type.DICE) {
- System.out.println(" (sample roll " + res.diceVal.value() + ")");
+ System.out.println("\t\t (sample roll " + res.diceVal.value() + ")");
}
}
@@ -544,11 +557,6 @@ public class DiceLangEngine {
tk = new Token(FLOAT_LIT, Double.parseDouble(token));
} else if(DiceBox.isValidExpression(token)) {
tk = new Token(DICE_LIT, DiceBox.parseExpression(token));
-
- if(debugMode)
- System.out.println("\tDEBUG: Parsed dice expression"
- + ", evaluated as: "
- + tk.diceValue.value());
} else {
Matcher stringLit = stringLitMatcher.matcher(token);
diff --git a/dice-lang/src/bjc/dicelang/v2/Errors.java b/dice-lang/src/bjc/dicelang/v2/Errors.java
index 0f4c52d..6ad74ab 100644
--- a/dice-lang/src/bjc/dicelang/v2/Errors.java
+++ b/dice-lang/src/bjc/dicelang/v2/Errors.java
@@ -45,6 +45,8 @@ public class Errors {
EK_EVAL_STRINGMATH,
// Attempted divide by zero
EK_EVAL_DIVZERO,
+ // Attempted to divide dice
+ EK_EVAL_DIVDICE,
// Unknown math operator
EK_EVAL_UNMATH,
// Unknown token reference
@@ -150,7 +152,8 @@ public class Errors {
System.out.printf("\tERROR: Unknown node in evaluator: %s\n", args[0]);
break;
case EK_EVAL_INVBIN:
- System.out.printf("\tERROR: Binary operators take 2 operand, not %s\n", args[0]);
+ System.out.printf("\tERROR: Binary operators take 2 operand, not %s\n"
+ + "\tProblem node is %s\n", args[0], args[1]);
break;
case EK_EVAL_UNBIN:
System.out.printf("\tERROR: Unknown binary operator %s\n", args[0]);
@@ -161,6 +164,9 @@ public class Errors {
case EK_EVAL_DIVZERO:
System.out.printf("\tERROR: Attempted divide by zero\n");
break;
+ case EK_EVAL_DIVDICE:
+ System.out.printf("\tERROR: Dice cannot be divided\n");
+ break;
case EK_EVAL_UNMATH:
System.out.printf("\tERROR: Unknown math binary operator: %s\n", args[0]);
break;
diff --git a/dice-lang/src/bjc/dicelang/v2/Evaluator.java b/dice-lang/src/bjc/dicelang/v2/Evaluator.java
index 7624b47..904c8bc 100644
--- a/dice-lang/src/bjc/dicelang/v2/Evaluator.java
+++ b/dice-lang/src/bjc/dicelang/v2/Evaluator.java
@@ -1,16 +1,24 @@
package bjc.dicelang.v2;
import bjc.utils.data.ITree;
+import bjc.utils.data.SingleIterator;
import bjc.utils.data.Tree;
import bjc.utils.data.TopDownTransformIterator;
import bjc.utils.data.TopDownTransformResult;
+
+import java.util.Deque;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.function.Consumer;
import static bjc.dicelang.v2.Errors.ErrorKey.*;
import static bjc.dicelang.v2.EvaluatorResult.Type.*;
public class Evaluator {
+ private static enum CoerceSteps {
+ INTEGER, FLOAT;
+ }
+
private static class Context {
public Consumer<Iterator<ITree<Node>>> thunk;
@@ -18,19 +26,19 @@ public class Evaluator {
}
private static Node FAIL() {
- return new Node(Node.Type.RESULT, new EvaluatorResult(EvaluatorResult.Type.FAILURE));
+ return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE));
}
private static Node FAIL(ITree<Node> orig) {
- return new Node(Node.Type.RESULT, new EvaluatorResult(EvaluatorResult.Type.FAILURE, orig));
+ return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, orig));
}
private static Node FAIL(Node orig) {
- return new Node(Node.Type.RESULT, new EvaluatorResult(EvaluatorResult.Type.FAILURE, orig));
+ return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, orig));
}
private static Node FAIL(EvaluatorResult res) {
- return new Node(Node.Type.RESULT, new EvaluatorResult(EvaluatorResult.Type.FAILURE, new Node(Node.Type.RESULT, res)));
+ return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, new Node(Node.Type.RESULT, res)));
}
private DiceLangEngine eng;
@@ -53,6 +61,7 @@ public class Evaluator {
(node) -> this.evaluateNode(node, ctx)).getHead().resultVal;
}
+ // @FIXME Something's broken with step evaluation
public Iterator<ITree<Node>> stepDebug(ITree<Node> comm) {
Context ctx = new Context();
@@ -89,6 +98,8 @@ public class Evaluator {
return evaluateTokenRef(ast.getHead().tokenVal, ctx);
case ROOT:
return ast.getChild(ast.getChildrenCount() - 1);
+ case RESULT:
+ return ast;
default:
Errors.inst.printError(EK_EVAL_INVNODE, ast.getHead().type.toString());
return new Tree<>(FAIL(ast));
@@ -102,21 +113,66 @@ public class Evaluator {
Errors.inst.printError(EK_EVAL_UNUNARY, Integer.toString(ast.getChildrenCount()));
return new Tree<>(FAIL(ast));
}
- break;
+
+ ITree<Node> toCoerce = ast.getChild(0);
+ ITree<Node> retVal = new Tree<>(toCoerce.getHead());
+ Deque<ITree<Node>> children = new LinkedList<>();
+
+ CoerceSteps curLevel = CoerceSteps.INTEGER;
+
+ for(int i = 0; i < toCoerce.getChildrenCount(); i++) {
+ ITree<Node> child = toCoerce.getChild(i);
+ ITree<Node> nChild = null;
+
+ if(ctx.isDebug) {
+ Iterator<ITree<Node>> nd = stepDebug(child);
+
+ for(; nd.hasNext(); nChild = nd.next()) {
+ ctx.thunk.accept(new SingleIterator(child));
+ }
+ } else {
+ nChild = new Tree<>(new Node(Node.Type.RESULT, evaluate(child)));
+
+ if(nChild != null) ctx.thunk.accept(new SingleIterator(nChild));
+ }
+
+ Node childNode = nChild.getHead();
+ EvaluatorResult res = childNode.resultVal;
+
+ if(res.type == FLOAT) curLevel = CoerceSteps.FLOAT;
+
+ children.add(nChild);
+ }
+
+ for(ITree<Node> child : children) {
+ Node nd = child.getHead();
+ EvaluatorResult res = nd.resultVal;
+
+ switch(res.type) {
+ case INT:
+ if(curLevel == CoerceSteps.FLOAT) {
+ nd.resultVal = new EvaluatorResult(FLOAT, (double)res.intVal);
+ }
+ default:
+ // Do nothing
+ break;
+ }
+
+ retVal.addChild(child);
+ }
+
+ return retVal;
default:
Errors.inst.printError(EK_EVAL_INVUNARY, ast.getHead().operatorType.toString());
return new Tree<>(FAIL(ast));
}
-
- // @TODO remove me
- return new Tree<>(FAIL(ast));
}
private ITree<Node> evaluateBinaryOp(ITree<Node> ast, Context ctx) {
Token.Type binOp = ast.getHead().operatorType;
if(ast.getChildrenCount() != 2) {
- Errors.inst.printError(EK_EVAL_INVBIN, Integer.toString(ast.getChildrenCount()));
+ Errors.inst.printError(EK_EVAL_INVBIN, Integer.toString(ast.getChildrenCount()), ast.toString());
return new Tree<>(FAIL(ast));
}
@@ -208,24 +264,27 @@ public class Evaluator {
private ITree<Node> evaluateMathBinary(Token.Type op,
EvaluatorResult left, EvaluatorResult right, Context ctx) {
- if(left.type == EvaluatorResult.Type.DICE || right.type == EvaluatorResult.Type.DICE) {
- System.out.println("\tEVALUATOR ERROR: Math on dice isn't supported yet");
- return new Tree<>(FAIL());
- } else if(left.type == EvaluatorResult.Type.STRING || right.type == EvaluatorResult.Type.STRING) {
+ if(left.type == STRING || right.type == STRING) {
Errors.inst.printError(EK_EVAL_STRINGMATH);
return new Tree<>(FAIL());
- } else if(left.type == EvaluatorResult.Type.FAILURE || right.type == EvaluatorResult.Type.FAILURE) {
+ } else if(left.type == FAILURE || right.type == FAILURE) {
return new Tree<>(FAIL());
- } else if(left.type == EvaluatorResult.Type.INT && right.type != EvaluatorResult.Type.INT) {
+ } else if(left.type == INT && right.type != INT) {
Errors.inst.printError(EK_EVAL_MISMATH);
return new Tree<>(FAIL(right));
- } else if(left.type == EvaluatorResult.Type.FLOAT && right.type != EvaluatorResult.Type.FLOAT) {
+ } else if(left.type == FLOAT && right.type != FLOAT) {
Errors.inst.printError(EK_EVAL_MISMATH);
return new Tree<>(FAIL(right));
- } else if(right.type == EvaluatorResult.Type.INT && left.type != EvaluatorResult.Type.INT) {
+ } else if(left.type == DICE && right.type != DICE) {
+ Errors.inst.printError(EK_EVAL_MISMATH);
+ return new Tree<>(FAIL(right));
+ } else if(right.type == INT && left.type != INT) {
+ Errors.inst.printError(EK_EVAL_MISMATH);
+ return new Tree<>(FAIL(left));
+ } else if(right.type == FLOAT && left.type != FLOAT) {
Errors.inst.printError(EK_EVAL_MISMATH);
return new Tree<>(FAIL(left));
- } else if(right.type == EvaluatorResult.Type.FLOAT && left.type != EvaluatorResult.Type.FLOAT) {
+ } else if(right.type == DICE && left.type != DICE) {
Errors.inst.printError(EK_EVAL_MISMATH);
return new Tree<>(FAIL(left));
}
@@ -234,58 +293,97 @@ public class Evaluator {
switch(op) {
case ADD:
- if(left.type == EvaluatorResult.Type.INT) {
- res = new EvaluatorResult(EvaluatorResult.Type.INT, left.intVal + right.intVal);
+ if(left.type == INT) {
+ res = new EvaluatorResult(INT, left.intVal + right.intVal);
+ } else if(left.type == DICE) {
+ if(left.diceVal.isList) {
+ Errors.inst.printError(EK_EVAL_INVDICE, left.toString());
+ return new Tree<>(FAIL(left));
+ } else if(right.diceVal.isList) {
+ Errors.inst.printError(EK_EVAL_INVDICE, right.toString());
+ return new Tree<>(FAIL(right));
+ }
+
+ res = new EvaluatorResult(DICE, new DiceBox.MathDie(DiceBox.MathDie.MathOp.ADD,
+ left.diceVal.scalar, right.diceVal.scalar));
} else {
- res = new EvaluatorResult(EvaluatorResult.Type.FLOAT, left.floatVal + right.floatVal);
+ res = new EvaluatorResult(FLOAT, left.floatVal + right.floatVal);
}
break;
case SUBTRACT:
- if(left.type == EvaluatorResult.Type.INT) {
- res = new EvaluatorResult(EvaluatorResult.Type.INT, left.intVal - right.intVal);
+ if(left.type == INT) {
+ res = new EvaluatorResult(INT, left.intVal - right.intVal);
+ } else if(left.type == DICE) {
+ if(left.diceVal.isList) {
+ Errors.inst.printError(EK_EVAL_INVDICE, left.toString());
+ return new Tree<>(FAIL(left));
+ } else if(right.diceVal.isList) {
+ Errors.inst.printError(EK_EVAL_INVDICE, right.toString());
+ return new Tree<>(FAIL(right));
+ }
+
+ res = new EvaluatorResult(DICE, new DiceBox.MathDie(DiceBox.MathDie.MathOp.SUBTRACT,
+ left.diceVal.scalar, right.diceVal.scalar));
} else {
- res = new EvaluatorResult(EvaluatorResult.Type.FLOAT, left.floatVal - right.floatVal);
+ res = new EvaluatorResult(FLOAT, left.floatVal - right.floatVal);
}
break;
case MULTIPLY:
- if(left.type == EvaluatorResult.Type.INT) {
- res = new EvaluatorResult(EvaluatorResult.Type.INT, left.intVal * right.intVal);
+ if(left.type == INT) {
+ res = new EvaluatorResult(INT, left.intVal * right.intVal);
+ } else if(left.type == DICE) {
+ if(left.diceVal.isList) {
+ Errors.inst.printError(EK_EVAL_INVDICE, left.toString());
+ return new Tree<>(FAIL(left));
+ } else if(right.diceVal.isList) {
+ Errors.inst.printError(EK_EVAL_INVDICE, right.toString());
+ return new Tree<>(FAIL(right));
+ }
+
+ res = new EvaluatorResult(DICE, new DiceBox.MathDie(DiceBox.MathDie.MathOp.MULTIPLY,
+ left.diceVal.scalar, right.diceVal.scalar));
} else {
- res = new EvaluatorResult(EvaluatorResult.Type.FLOAT, left.floatVal * right.floatVal);
+ res = new EvaluatorResult(FLOAT, left.floatVal * right.floatVal);
}
break;
case DIVIDE:
- if(left.type == EvaluatorResult.Type.INT) {
+ if(left.type == INT) {
if(right.intVal == 0) {
Errors.inst.printError(EK_EVAL_DIVZERO);
- res = new EvaluatorResult(EvaluatorResult.Type.FAILURE, right);
+ res = new EvaluatorResult(FAILURE, right);
} else {
- res = new EvaluatorResult(EvaluatorResult.Type.FLOAT, left.intVal / right.intVal);
+ res = new EvaluatorResult(FLOAT, left.intVal / right.intVal);
}
- } else {
+ } else if(left.type == FLOAT) {
if(right.floatVal == 0) {
Errors.inst.printError(EK_EVAL_DIVZERO);
- res = new EvaluatorResult(EvaluatorResult.Type.FAILURE, right);
+ res = new EvaluatorResult(FAILURE, right);
} else {
- res = new EvaluatorResult(EvaluatorResult.Type.FLOAT, left.floatVal / right.floatVal);
+ res = new EvaluatorResult(FLOAT, left.floatVal / right.floatVal);
}
+ } else {
+ Errors.inst.printError(EK_EVAL_DIVDICE);
+ return new Tree<>(FAIL());
}
break;
case IDIVIDE:
- if(left.type == EvaluatorResult.Type.INT) {
+ if(left.type == INT) {
if(right.intVal == 0) {
Errors.inst.printError(EK_EVAL_DIVZERO);
- res = new EvaluatorResult(EvaluatorResult.Type.FAILURE, right);
+ res = new EvaluatorResult(FAILURE, right);
} else {
- res = new EvaluatorResult(EvaluatorResult.Type.INT, (int) (left.intVal / right.intVal));
+ res = new EvaluatorResult(INT, (int) (left.intVal / right.intVal));
}
- } else {
+ } else if(left.type == FLOAT) {
if(right.floatVal == 0) {
Errors.inst.printError(EK_EVAL_DIVZERO);
- res = new EvaluatorResult(EvaluatorResult.Type.FAILURE, right);
+ res = new EvaluatorResult(FAILURE, right);
} else {
- res = new EvaluatorResult(EvaluatorResult.Type.INT, (int) (left.floatVal / right.floatVal));
+ res = new EvaluatorResult(INT, (int) (left.floatVal / right.floatVal));
}
+ } else {
+ Errors.inst.printError(EK_EVAL_DIVDICE);
+ return new Tree<>(FAIL());
}
break;
default:
@@ -301,20 +399,20 @@ public class Evaluator {
switch(tk.type) {
case INT_LIT:
- res = new EvaluatorResult(EvaluatorResult.Type.INT, tk.intValue);
+ res = new EvaluatorResult(INT, tk.intValue);
break;
case FLOAT_LIT:
- res = new EvaluatorResult(EvaluatorResult.Type.FLOAT, tk.floatValue);
+ res = new EvaluatorResult(FLOAT, tk.floatValue);
break;
case DICE_LIT:
- res = new EvaluatorResult(EvaluatorResult.Type.DICE, tk.diceValue);
+ res = new EvaluatorResult(DICE, tk.diceValue);
break;
case STRING_LIT:
- res = new EvaluatorResult(EvaluatorResult.Type.STRING, eng.stringLits.get((int)(tk.intValue)));
+ res = new EvaluatorResult(STRING, eng.stringLits.get((int)(tk.intValue)));
break;
default:
Errors.inst.printError(EK_EVAL_UNTOK, tk.type.toString());
- res = new EvaluatorResult(EvaluatorResult.Type.FAILURE);
+ res = new EvaluatorResult(FAILURE);
}
return new Tree<>(new Node(Node.Type.RESULT, res));
diff --git a/dice-lang/src/bjc/dicelang/v2/Shunter.java b/dice-lang/src/bjc/dicelang/v2/Shunter.java
index e95b642..d5f9135 100644
--- a/dice-lang/src/bjc/dicelang/v2/Shunter.java
+++ b/dice-lang/src/bjc/dicelang/v2/Shunter.java
@@ -43,26 +43,29 @@ public class Shunter {
unaryAdjectives.add(COERCE);
- ops.put(ADD, 0 + MATH_PREC);
- ops.put(SUBTRACT, 0 + MATH_PREC);
+ ops.put(ADD, 0 + MATH_PREC);
+ ops.put(SUBTRACT, 0 + MATH_PREC);
- ops.put(MULTIPLY, 1 + MATH_PREC);
- ops.put(IDIVIDE, 1 + MATH_PREC);
- ops.put(DIVIDE, 1 + MATH_PREC);
+ ops.put(MULTIPLY, 1 + MATH_PREC);
+ ops.put(IDIVIDE, 1 + MATH_PREC);
+ ops.put(DIVIDE, 1 + MATH_PREC);
ops.put(DICEGROUP, 0 + DICE_PREC);
+
ops.put(DICECONCAT, 1 + DICE_PREC);
+
ops.put(DICELIST, 2 + DICE_PREC);
- ops.put(LET, 0 + EXPR_PREC);
- ops.put(BIND, 1 + EXPR_PREC);
+ ops.put(LET, 0 + EXPR_PREC);
+ ops.put(BIND, 1 + EXPR_PREC);
}
private boolean isUnary(Token ty) {
- switch(ty.type) {
- default:
- return false;
- }
+ if(unaryAdjectives.contains(ty)) return true;
+ if(unaryAdverbs.contains(ty)) return true;
+ if(unaryGerunds.contains(ty)) return true;
+
+ return false;
}
private boolean isOp(Token tk) {
@@ -77,111 +80,119 @@ public class Shunter {
return false;
}
- public boolean shuntTokens(IList<Token> tks, IList<Token> returned) {
- Deque<Token> opStack = new LinkedList<>();
+ private boolean shuntToken(Token tk, Deque<Token> opStack,
+ Deque<Token> unaryStack, Deque<Token> currReturned,
+ Deque<Token> feed) {
+ if(unaryStack.size() != 0) {
+ if(isUnary(tk)) {
+ unaryStack.add(tk);
+ return true;
+ }
- boolean unaryMode = false;
- Deque<Token> unaryOps = new LinkedList<>();
+ Token unaryOp = unaryStack.pop();
- Deque<Token> currReturned = new LinkedList<>();
+ Token.Type unaryType = unaryOp.type;
- for(Token tk : tks.toIterable()) {
- if(unaryMode) {
- if(isUnary(tk)) {
- unaryOps.add(tk);
- continue;
+ if(unaryAdjectives.contains(unaryType)) {
+ if(isOp(tk)) {
+ Errors.inst.printError(EK_SHUNT_NOTADV, unaryOp.toString(), tk.toString());
+ return false;
}
- Token unaryOp = unaryOps.pop();
-
- Token.Type unaryType = unaryOp.type;
-
- if(unaryAdjectives.contains(unaryType)) {
- if(isOp(tk)) {
- Errors.inst.printError(EK_SHUNT_NOTADV, unaryOp.toString(), tk.toString());
- return false;
- }
-
- Token newTok = new Token(TAGOPR);
-
- if(tk.type == TAGOP) {
- newTok.tokenValues = tk.tokenValues;
- } else {
- newTok.tokenValues = new FunctionalList<>();
- }
-
- newTok.tokenValues.add(unaryOp);
- opStack.push(newTok);
- } else if(unaryAdverbs.contains(unaryType)) {
- // @TODO finish implementing unary operators
- // this will require adding a 'backfeed' to the shunter to catch
- // tokens we missed while parsing unary operators
+ Token newTok = new Token(TAGOPR);
+
+ if(tk.type == TAGOP) {
+ newTok.tokenValues = tk.tokenValues;
+ } else {
+ newTok.tokenValues = new FunctionalList<>();
}
- }
- if(isUnary(tk)) {
- unaryMode = true;
+ newTok.tokenValues.add(unaryOp);
+ opStack.push(newTok);
- unaryOps.add(tk);
- continue;
- } else if(isOp(tk)) {
- while(!opStack.isEmpty() && isHigherPrec(tk, opStack.peek())) {
- currReturned.addLast(opStack.pop());
- }
+ return true;
+ } else if(unaryAdverbs.contains(unaryType)) {
+
+ }
+ }
- opStack.push(tk);
- } else if(tk.type == OPAREN || tk.type == OBRACE) {
- opStack.push(tk);
-
- if(tk.type == OBRACE) currReturned.addLast(tk);
- } else if(tk.type == CPAREN || tk.type == CBRACE) {
- Token matching = null;
-
- switch(tk.type) {
- case CPAREN:
- matching = new Token(OPAREN, tk.intValue);
- break;
- case CBRACE:
- matching = new Token(OBRACE, tk.intValue);
- break;
- default:
- break;
- }
+ if(isUnary(tk)) {
+ unaryStack.add(tk);
+ return true;
+ } else if(isOp(tk)) {
+ while(!opStack.isEmpty() && isHigherPrec(tk, opStack.peek())) {
+ currReturned.addLast(opStack.pop());
+ }
- if(!opStack.contains(matching)) {
- Errors.inst.printError(EK_SHUNT_NOGROUP, tk.toString(), matching.toString());
- return false;
- }
+ opStack.push(tk);
+ } else if(tk.type == OPAREN || tk.type == OBRACE) {
+ opStack.push(tk);
+
+ if(tk.type == OBRACE) currReturned.addLast(tk);
+ } else if(tk.type == CPAREN || tk.type == CBRACE) {
+ Token matching = null;
+
+ switch(tk.type) {
+ case CPAREN:
+ matching = new Token(OPAREN, tk.intValue);
+ break;
+ case CBRACE:
+ matching = new Token(OBRACE, tk.intValue);
+ break;
+ default:
+ break;
+ }
- while(!opStack.peek().equals(matching)) {
- currReturned.addLast(opStack.pop());
- }
+ if(!opStack.contains(matching)) {
+ Errors.inst.printError(EK_SHUNT_NOGROUP, tk.toString(), matching.toString());
+ return false;
+ }
- if(tk.type == CBRACE) {
- currReturned.addLast(tk);
- }
+ while(!opStack.peek().equals(matching)) {
+ currReturned.addLast(opStack.pop());
+ }
- opStack.pop();
- } else if(tk.type == GROUPSEP) {
- IList<Token> group = new FunctionalList<>();
+ if(tk.type == CBRACE) {
+ currReturned.addLast(tk);
+ }
- while(currReturned.size() != 0 && !currReturned.peek().isGrouper()) {
- group.add(currReturned.pop());
- }
+ opStack.pop();
+ } else if(tk.type == GROUPSEP) {
+ IList<Token> group = new FunctionalList<>();
- while(opStack.size() != 0 && !opStack.peek().isGrouper()) {
- group.add(opStack.pop());
- }
+ while(currReturned.size() != 0 && !currReturned.peek().isGrouper()) {
+ group.add(currReturned.pop());
+ }
- if(currReturned.size() == 0) {
- Errors.inst.printError(EK_SHUNT_INVSEP);
- return false;
- }
+ while(opStack.size() != 0 && !opStack.peek().isGrouper()) {
+ group.add(opStack.pop());
+ }
- currReturned.addLast(new Token(TOKGROUP, group));
- } else {
- currReturned.addLast(tk);
+ if(currReturned.size() == 0) {
+ Errors.inst.printError(EK_SHUNT_INVSEP);
+ return false;
}
+
+ currReturned.addLast(new Token(TOKGROUP, group));
+ } else {
+ currReturned.addLast(tk);
+ }
+
+ return true;
+ }
+
+ public boolean shuntTokens(IList<Token> tks, IList<Token> returned) {
+ Deque<Token> opStack = new LinkedList<>();
+ Deque<Token> unaryOps = new LinkedList<>();
+
+ Deque<Token> currReturned = new LinkedList<>();
+
+ Deque<Token> feed = new LinkedList<>();
+
+ for(Token tk : tks.toIterable()) {
+ while(feed.size() != 0)
+ shuntToken(feed.poll(), opStack, unaryOps, currReturned, feed);
+ shuntToken(tk, opStack, unaryOps, currReturned, feed);
}
// Flush leftover operators
@@ -202,13 +213,27 @@ public class Shunter {
boolean exists = ops.containsKey(right);
+ if(rght.type == TAGOPR) exists = true;
+
// If it doesn't, the left is higher precedence.
if (!exists) {
return false;
}
- int rightPrecedence = ops.get(right);
- int leftPrecedence = ops.get(left);
+ int rightPrecedence;
+ int leftPrecedence;
+
+ if(rght.type == TAGOPR) {
+ rightPrecedence = (int)rght.intValue;
+ } else {
+ rightPrecedence = ops.get(right);
+ }
+
+ if(lft.type == TAGOPR) {
+ leftPrecedence = (int)lft.intValue;
+ } else {
+ leftPrecedence = ops.get(left);
+ }
return rightPrecedence >= leftPrecedence;
}
diff --git a/dice-lang/src/bjc/dicelang/v2/StreamEngine.java b/dice-lang/src/bjc/dicelang/v2/StreamEngine.java
index 383c7f3..41f01a7 100644
--- a/dice-lang/src/bjc/dicelang/v2/StreamEngine.java
+++ b/dice-lang/src/bjc/dicelang/v2/StreamEngine.java
@@ -41,7 +41,7 @@ public class StreamEngine {
} else {
if(tk.equals("{@SU}")) {
quoteMode = false;
- } else if(tk.matches("\\\\+{@SU}")) {
+ } else if(tk.startsWith("\\") && tk.endsWith("{@SU}")) {
currStream.add(tk.substring(1));
} else {
currStream.add(tk);