summaryrefslogtreecommitdiff
path: root/dice-lang/src
diff options
context:
space:
mode:
Diffstat (limited to 'dice-lang/src')
-rw-r--r--dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java21
-rw-r--r--dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java2
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/ArithmeticCollapser.java134
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/ArrayResult.java43
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java125
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTParser.java73
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceSanitizer.java119
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java4
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/IResult.java16
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/IntegerResult.java40
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/ResultType.java18
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java6
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/optimization/ConstantCollapser.java6
-rw-r--r--dice-lang/src/main/java/bjc/dicelang/ast/optimization/OperationCondenser.java1
14 files changed, 548 insertions, 60 deletions
diff --git a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java
index a6d5c75..fb4b086 100644
--- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java
+++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceASTLanguageTest.java
@@ -7,6 +7,7 @@ import bjc.dicelang.ast.DiceASTInliner;
import bjc.dicelang.ast.DiceASTOptimizer;
import bjc.dicelang.ast.DiceASTParser;
import bjc.dicelang.ast.DiceASTReferenceSanitizer;
+import bjc.dicelang.ast.IResult;
import bjc.dicelang.ast.nodes.IDiceASTNode;
import bjc.dicelang.ast.optimization.ConstantCollapser;
import bjc.dicelang.ast.optimization.OperationCondenser;
@@ -114,7 +115,7 @@ public class DiceASTLanguageTest {
IFunctionalList<String> preparedTokens =
DiceExpressionPreparer.prepareCommand(currentLine);
-
+
try {
builtAST = DiceASTParser.createFromString(preparedTokens);
} catch (IllegalStateException isex) {
@@ -125,11 +126,17 @@ public class DiceASTLanguageTest {
continue;
}
- int sampleRoll;
+ // Print out results
+ System.out.println("\tParsed: " + builtAST.toString());
ITree<IDiceASTNode> transformedAST =
transformAST(builtAST, enviroment);
+ System.out
+ .println("\tEvaluated: " + transformedAST.toString());
+
+ IResult sampleRoll;
+
try {
sampleRoll = DiceASTEvaluator.evaluateAST(transformedAST,
enviroment);
@@ -143,10 +150,6 @@ public class DiceASTLanguageTest {
continue;
}
- // Print out results
- System.out.println("\tParsed: " + builtAST.toString());
- System.out
- .println("\tEvaluated: " + transformedAST.toString());
System.out.println("\t\tSample Roll: " + sampleRoll);
// Increase the number of commands
@@ -173,7 +176,11 @@ public class DiceASTLanguageTest {
ITree<IDiceASTNode> sanitizedTree = DiceASTReferenceSanitizer
.sanitize(condensedTree, enviroment);
- return sanitizedTree;
+ optimizedTree = optimizer.optimizeTree(sanitizedTree, enviroment);
+
+ condensedTree = OperationCondenser.condense(optimizedTree);
+
+ return condensedTree;
}
private static String getNextCommand(Scanner inputSource,
diff --git a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java
index caf7f37..4524fa0 100644
--- a/dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java
+++ b/dice-lang/src/examples/java/bjc/dicelang/examples/DiceExpressionPreparer.java
@@ -67,6 +67,8 @@ public class DiceExpressionPreparer {
ops.add(new Pair<>("(", "\\("));
ops.add(new Pair<>(")", "\\)"));
+ ops.add(new Pair<>("[", "\\["));
+ ops.add(new Pair<>("]", "\\]"));
IFunctionalList<String> fullyExpandedTokens =
ListUtils.deAffixTokens(semiExpandedTokens, ops);
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/ArithmeticCollapser.java b/dice-lang/src/main/java/bjc/dicelang/ast/ArithmeticCollapser.java
index 5c00fe2..ad508c8 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/ArithmeticCollapser.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/ArithmeticCollapser.java
@@ -28,12 +28,12 @@ final class ArithmeticCollapser implements IOperatorCollapser {
}
@Override
- public IPair<Integer, ITree<IDiceASTNode>> apply(
- IFunctionalList<IPair<Integer, ITree<IDiceASTNode>>> nodes) {
- IPair<Integer, ITree<IDiceASTNode>> initState =
- new Pair<>(0, new Tree<>(type));
+ public IPair<IResult, ITree<IDiceASTNode>> apply(
+ IFunctionalList<IPair<IResult, ITree<IDiceASTNode>>> nodes) {
+ IPair<IResult, ITree<IDiceASTNode>> initState =
+ new Pair<>(new IntegerResult(0), new Tree<>(type));
- BinaryOperator<IPair<Integer, ITree<IDiceASTNode>>> reducer =
+ BinaryOperator<IPair<IResult, ITree<IDiceASTNode>>> reducer =
(currentState, accumulatedState) -> {
// Force evaluation of accumulated state to prevent
// certain bugs from occuring
@@ -42,27 +42,133 @@ final class ArithmeticCollapser implements IOperatorCollapser {
return reduceStates(accumulatedState, currentState);
};
- IPair<Integer, ITree<IDiceASTNode>> reducedState =
+ IPair<IResult, ITree<IDiceASTNode>> reducedState =
nodes.reduceAux(initState, reducer, (state) -> state);
return reducedState;
}
- private IPair<Integer, ITree<IDiceASTNode>> reduceStates(
- IPair<Integer, ITree<IDiceASTNode>> accumulatedState,
- IPair<Integer, ITree<IDiceASTNode>> currentState) {
+ private IPair<IResult, ITree<IDiceASTNode>> reduceStates(
+ IPair<IResult, ITree<IDiceASTNode>> accumulatedState,
+ IPair<IResult, ITree<IDiceASTNode>> currentState) {
return accumulatedState
.bind((accumulatedValue, accumulatedTree) -> {
return currentState
.bind((currentValue, currentTree) -> {
accumulatedTree.addChild(currentTree);
- Integer combinedValue = valueOp.apply(
- accumulatedValue, currentValue);
-
- return new Pair<>(combinedValue,
- accumulatedTree);
+ return doArithmeticCollapse(
+ accumulatedValue, accumulatedTree,
+ currentValue);
});
});
}
+
+ private IPair<IResult, ITree<IDiceASTNode>> doArithmeticCollapse(
+ IResult accumulatedValue, ITree<IDiceASTNode> accumulatedTree,
+ IResult currentValue) {
+ boolean currentIsInt =
+ currentValue.getType() == ResultType.INTEGER;
+ boolean accumulatedIsInt =
+ accumulatedValue.getType() == ResultType.INTEGER;
+
+ if (!currentIsInt) {
+ if (!accumulatedIsInt) {
+ IFunctionalList<IResult> resultList = combineArrayResults(
+ accumulatedValue, currentValue);
+
+ return new Pair<>(new ArrayResult(resultList),
+ accumulatedTree);
+ }
+
+ IFunctionalList<IResult> resultList = halfCombineLists(
+ ((ArrayResult) currentValue).getValue(),
+ accumulatedValue, true);
+
+ return new Pair<>(new ArrayResult(resultList),
+ accumulatedTree);
+ } else if (!accumulatedIsInt) {
+ IFunctionalList<IResult> resultList = halfCombineLists(
+ ((ArrayResult) accumulatedValue).getValue(),
+ currentValue, false);
+
+ return new Pair<>(new ArrayResult(resultList),
+ accumulatedTree);
+ }
+
+ int accumulatedInt = ((IntegerResult) accumulatedValue).getValue();
+ int currentInt = ((IntegerResult) currentValue).getValue();
+
+ int combinedValue = valueOp.apply(accumulatedInt, currentInt);
+
+ return new Pair<>(new IntegerResult(combinedValue),
+ accumulatedTree);
+ }
+
+ private IFunctionalList<IResult> combineArrayResults(
+ IResult accumulatedValue, IResult currentValue) {
+ IFunctionalList<IResult> currentList =
+ ((ArrayResult) currentValue).getValue();
+ IFunctionalList<IResult> accumulatedList =
+ ((ArrayResult) accumulatedValue).getValue();
+
+ if (currentList.getSize() != accumulatedList.getSize()) {
+ throw new UnsupportedOperationException(
+ "Can only apply operations to equal-length arrays");
+ }
+
+ IFunctionalList<IResult> resultList = currentList.combineWith(
+ accumulatedList, (currentNode, accumulatedNode) -> {
+ boolean currentNotInt =
+ currentNode.getType() != ResultType.INTEGER;
+ boolean accumulatedNotInt = accumulatedNode
+ .getType() != ResultType.INTEGER;
+
+ if (currentNotInt || accumulatedNotInt) {
+ throw new UnsupportedOperationException(
+ "Nesting of array operations isn't allowed");
+ }
+
+ int accumulatedInt =
+ ((IntegerResult) accumulatedNode).getValue();
+ int currentInt =
+ ((IntegerResult) currentNode).getValue();
+
+ IResult combinedValue = new IntegerResult(
+ valueOp.apply(accumulatedInt, currentInt));
+ return combinedValue;
+ });
+ return resultList;
+ }
+
+ private IFunctionalList<IResult> halfCombineLists(
+ IFunctionalList<IResult> list, IResult scalar,
+ boolean scalarLeft) {
+ if (scalar.getType() != ResultType.INTEGER) {
+ throw new UnsupportedOperationException(
+ "Nested array operations not supported");
+ }
+
+ int scalarInt = ((IntegerResult) scalar).getValue();
+
+ return list.map((element) -> {
+ if (element.getType() != ResultType.INTEGER) {
+ throw new UnsupportedOperationException(
+ "Nested array operations not supported");
+ }
+ int elementInt = ((IntegerResult) element).getValue();
+
+ IResult combinedValue;
+
+ if (scalarLeft) {
+ combinedValue = new IntegerResult(
+ valueOp.apply(scalarInt, elementInt));
+ } else {
+ combinedValue = new IntegerResult(
+ valueOp.apply(elementInt, scalarInt));
+ }
+
+ return combinedValue;
+ });
+ }
} \ No newline at end of file
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/ArrayResult.java b/dice-lang/src/main/java/bjc/dicelang/ast/ArrayResult.java
new file mode 100644
index 0000000..1bd0940
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/ArrayResult.java
@@ -0,0 +1,43 @@
+package bjc.dicelang.ast;
+
+import bjc.utils.funcdata.IFunctionalList;
+
+/**
+ * Represents a result that is an array of other results
+ *
+ * @author ben
+ *
+ * TODO finish implementing me
+ */
+public class ArrayResult implements IResult {
+ private IFunctionalList<IResult> arrayContents;
+
+ /**
+ * Create a new array-valued result
+ *
+ * @param results
+ * The results in the array
+ */
+ public ArrayResult(IFunctionalList<IResult> results) {
+ this.arrayContents = results;
+ }
+
+ @Override
+ public ResultType getType() {
+ return ResultType.ARRAY;
+ }
+
+ /**
+ * Get the value of this result
+ *
+ * @return The value of this result
+ */
+ public IFunctionalList<IResult> getValue() {
+ return arrayContents;
+ }
+
+ @Override
+ public String toString() {
+ return arrayContents.toString();
+ }
+}
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java
index aeecb38..7d073d4 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTEvaluator.java
@@ -1,6 +1,7 @@
package bjc.dicelang.ast;
import bjc.dicelang.ComplexDice;
+import bjc.dicelang.ast.nodes.DiceASTType;
import bjc.dicelang.ast.nodes.DiceLiteralNode;
import bjc.dicelang.ast.nodes.DiceLiteralType;
import bjc.dicelang.ast.nodes.IDiceASTNode;
@@ -8,9 +9,12 @@ import bjc.dicelang.ast.nodes.ILiteralDiceNode;
import bjc.dicelang.ast.nodes.IntegerLiteralNode;
import bjc.dicelang.ast.nodes.OperatorDiceNode;
import bjc.dicelang.ast.nodes.VariableDiceNode;
+import bjc.utils.data.IHolder;
import bjc.utils.data.IPair;
+import bjc.utils.data.Identity;
import bjc.utils.data.LazyPair;
import bjc.utils.data.Pair;
+import bjc.utils.funcdata.FunctionalList;
import bjc.utils.funcdata.FunctionalMap;
import bjc.utils.funcdata.IFunctionalList;
import bjc.utils.funcdata.IFunctionalMap;
@@ -71,12 +75,27 @@ public class DiceASTEvaluator {
return parseLet(enviroment, nodes);
});
+ operatorCollapsers.put(OperatorDiceNode.ARRAY, (nodes) -> {
+ ITree<IDiceASTNode> returnedTree =
+ new Tree<>(OperatorDiceNode.ARRAY);
+ IFunctionalList<IResult> resultList = new FunctionalList<>();
+
+ nodes.forEach((element) -> {
+ element.doWith((result, tree) -> {
+ resultList.add(result);
+ returnedTree.addChild(tree);
+ });
+ });
+
+ return new Pair<>(new ArrayResult(resultList), returnedTree);
+ });
+
return operatorCollapsers;
}
- private static IPair<Integer, ITree<IDiceASTNode>> parseLet(
+ private static IPair<IResult, ITree<IDiceASTNode>> parseLet(
IFunctionalMap<String, ITree<IDiceASTNode>> enviroment,
- IFunctionalList<IPair<Integer, ITree<IDiceASTNode>>> nodes) {
+ IFunctionalList<IPair<IResult, ITree<IDiceASTNode>>> nodes) {
if (nodes.getSize() != 2) {
throw new UnsupportedOperationException(
"Can only use let with two expressions.");
@@ -90,7 +109,7 @@ public class DiceASTEvaluator {
enviroment.extend();
evaluateAST(bindTree, letEnviroment);
- int exprResult = evaluateAST(expressionTree, letEnviroment);
+ IResult exprResult = evaluateAST(expressionTree, letEnviroment);
IFunctionalList<ITree<IDiceASTNode>> childrn =
nodes.map((pair) -> pair.getRight());
@@ -108,7 +127,7 @@ public class DiceASTEvaluator {
* The enviroment to look up variables in
* @return The integer value of the expression
*/
- public static int evaluateAST(ITree<IDiceASTNode> expression,
+ public static IResult evaluateAST(ITree<IDiceASTNode> expression,
IFunctionalMap<String, ITree<IDiceASTNode>> enviroment) {
IFunctionalMap<IDiceASTNode, IOperatorCollapser> collapsers =
buildOperations(enviroment);
@@ -118,7 +137,7 @@ public class DiceASTEvaluator {
(pair) -> pair.getLeft());
}
- private static IPair<Integer, ITree<IDiceASTNode>> evaluateLeaf(
+ private static IPair<IResult, ITree<IDiceASTNode>> evaluateLeaf(
IDiceASTNode leafNode,
IFunctionalMap<String, ITree<IDiceASTNode>> enviroment) {
ITree<IDiceASTNode> returnedAST = new Tree<>(leafNode);
@@ -139,31 +158,35 @@ public class DiceASTEvaluator {
}
}
- private static Integer bindLiteralValue(IDiceASTNode leafNode,
+ private static IResult bindLiteralValue(IDiceASTNode leafNode,
IFunctionalMap<String, ITree<IDiceASTNode>> enviroment) {
String variableName = ((VariableDiceNode) leafNode).getVariable();
if (enviroment.containsKey(variableName)) {
- int result =
+ IResult result =
evaluateAST(enviroment.get(variableName), enviroment);
return result;
}
- throw new UnsupportedOperationException(
- "Attempted to dereference unbound variable "
- + variableName);
+ // Allow for array assignment easily
+ return new IntegerResult(0);
}
- private static int evaluateLiteral(IDiceASTNode leafNode) {
+ private static IResult evaluateLiteral(IDiceASTNode leafNode) {
DiceLiteralType literalType =
((ILiteralDiceNode) leafNode).getLiteralType();
switch (literalType) {
case DICE:
- return ((DiceLiteralNode) leafNode).getValue().roll();
+ int diceRoll =
+ ((DiceLiteralNode) leafNode).getValue().roll();
+
+ return new IntegerResult(diceRoll);
case INTEGER:
- return ((IntegerLiteralNode) leafNode).getValue();
+ int val = ((IntegerLiteralNode) leafNode).getValue();
+
+ return new IntegerResult(val);
default:
throw new UnsupportedOperationException("Literal value '"
+ leafNode + "' is of a type (" + literalType
@@ -171,22 +194,19 @@ public class DiceASTEvaluator {
}
}
- private static IPair<Integer, ITree<IDiceASTNode>> parseBinding(
+ private static IPair<IResult, ITree<IDiceASTNode>> parseBinding(
IFunctionalMap<String, ITree<IDiceASTNode>> enviroment,
- IFunctionalList<IPair<Integer, ITree<IDiceASTNode>>> nodes) {
+ IFunctionalList<IPair<IResult, ITree<IDiceASTNode>>> nodes) {
if (nodes.getSize() != 2) {
throw new UnsupportedOperationException(
"Can only bind nodes with two children. Problem children are "
+ nodes);
}
- IPair<Integer, ITree<IDiceASTNode>> nameNode = nodes.getByIndex(0);
- IPair<Integer, ITree<IDiceASTNode>> valueNode =
+ IPair<IResult, ITree<IDiceASTNode>> nameNode = nodes.getByIndex(0);
+ IPair<IResult, ITree<IDiceASTNode>> valueNode =
nodes.getByIndex(1);
- // Force valueNode to materialize for debugging purposes
- valueNode.merge((l, r) -> null);
-
return nameNode.bindRight((nameTree) -> {
return valueNode.bind((valueValue, valueTree) -> {
if (DiceASTUtils.containsSimpleVariable(nameTree)) {
@@ -197,6 +217,36 @@ public class DiceASTEvaluator {
enviroment.put(varName, valueTree);
return new Pair<>(valueValue, nameTree);
+ } else if (nameTree.getHead() == OperatorDiceNode.ARRAY) {
+ if (valueTree.getHead() == OperatorDiceNode.ARRAY) {
+ if (nameTree.getChildrenCount() != valueTree
+ .getChildrenCount()) {
+ throw new UnsupportedOperationException(
+ "Array assignment must be between two equal length arrays");
+ }
+
+ IHolder<Integer> childCount = new Identity<>(0);
+
+ nameTree.doForChildren((child) -> {
+ doArrayAssign(enviroment, nameNode, nameTree,
+ valueTree, childCount, child);
+
+ childCount.transform(val -> val + 1);
+ });
+
+ return new Pair<>(valueValue, nameTree);
+ }
+
+ nameTree.doForChildren((child) -> {
+ String varName = child.transformHead((nameNod) -> {
+ return ((VariableDiceNode) nameNod)
+ .getVariable();
+ });
+
+ enviroment.put(varName, valueTree);
+ });
+
+ return new Pair<>(valueValue, nameTree);
}
throw new UnsupportedOperationException(
@@ -206,24 +256,45 @@ public class DiceASTEvaluator {
});
}
- private static IPair<Integer, ITree<IDiceASTNode>> parseGroup(
- IFunctionalList<IPair<Integer, ITree<IDiceASTNode>>> nodes) {
+ private static void doArrayAssign(
+ IFunctionalMap<String, ITree<IDiceASTNode>> enviroment,
+ IPair<IResult, ITree<IDiceASTNode>> nameNode,
+ ITree<IDiceASTNode> nameTree, ITree<IDiceASTNode> valueTree,
+ IHolder<Integer> childCount, ITree<IDiceASTNode> child) {
+ if (nameTree.getHead().getType() != DiceASTType.VARIABLE) {
+ throw new UnsupportedOperationException(
+ "Assigning to complex variables isn't supported. Problem node is "
+ + nameNode.getRight());
+ }
+
+ String varName = child.transformHead((nameNod) -> {
+ return ((VariableDiceNode) nameNod).getVariable();
+ });
+
+ enviroment.put(varName, valueTree.getChild(childCount.getValue()));
+
+ childCount.transform(val -> val + 1);
+ }
+
+ private static IPair<IResult, ITree<IDiceASTNode>> parseGroup(
+ IFunctionalList<IPair<IResult, ITree<IDiceASTNode>>> nodes) {
if (nodes.getSize() != 2) {
throw new UnsupportedOperationException(
"Can only form a group from two dice");
}
- IPair<Integer, ITree<IDiceASTNode>> numberDiceNode =
+ IPair<IResult, ITree<IDiceASTNode>> numberDiceNode =
nodes.getByIndex(0);
- IPair<Integer, ITree<IDiceASTNode>> diceTypeNode =
+ IPair<IResult, ITree<IDiceASTNode>> diceTypeNode =
nodes.getByIndex(1);
return numberDiceNode.bind((numberDiceValue, numberDiceTree) -> {
return diceTypeNode.bind((diceTypeValue, diceTypeTree) -> {
- ComplexDice cDice =
- new ComplexDice(numberDiceValue, diceTypeValue);
+ ComplexDice cDice = new ComplexDice(
+ ((IntegerResult) numberDiceValue).getValue(),
+ ((IntegerResult) diceTypeValue).getValue());
- return new Pair<>(cDice.roll(),
+ return new Pair<>(new IntegerResult(cDice.roll()),
new Tree<>(OperatorDiceNode.GROUP, numberDiceTree,
diceTypeTree));
});
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTParser.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTParser.java
index d8c94dc..c746c8b 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTParser.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTParser.java
@@ -1,6 +1,9 @@
package bjc.dicelang.ast;
+import java.util.Deque;
import java.util.InputMismatchException;
+import java.util.function.Function;
+import java.util.function.Predicate;
import bjc.dicelang.IDiceExpression;
import bjc.dicelang.ast.nodes.DiceLiteralNode;
@@ -10,8 +13,13 @@ import bjc.dicelang.ast.nodes.ILiteralDiceNode;
import bjc.dicelang.ast.nodes.IntegerLiteralNode;
import bjc.dicelang.ast.nodes.OperatorDiceNode;
import bjc.dicelang.ast.nodes.VariableDiceNode;
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.FunctionalMap;
import bjc.utils.funcdata.IFunctionalList;
+import bjc.utils.funcdata.IFunctionalMap;
import bjc.utils.funcdata.ITree;
+import bjc.utils.funcdata.Tree;
+import bjc.utils.funcutils.StringUtils;
import bjc.utils.parserutils.TreeConstructor;
/**
@@ -30,22 +38,77 @@ public class DiceASTParser {
*/
public static ITree<IDiceASTNode>
createFromString(IFunctionalList<String> tokens) {
+ Predicate<String> specialPicker = (operator) -> {
+ if (StringUtils.containsOnly(operator, "\\[")) {
+ return true;
+ } else if (StringUtils.containsOnly(operator, "\\]")) {
+ return true;
+ }
+
+ return false;
+ };
+
+ IFunctionalMap<String, Function<Deque<ITree<String>>, ITree<String>>> operators =
+ new FunctionalMap<>();
+
+ operators.put("[", (queuedTrees) -> {
+ Tree<String> openTree = new Tree<>("[");
+
+ return openTree;
+ });
+
+ operators.put("]", (queuedTrees) -> {
+ return parseCloseArray(queuedTrees);
+ });
+
ITree<String> rawTokens =
TreeConstructor.constructTree(tokens, (token) -> {
return isOperatorNode(token);
- }, (operator) -> false, null);
-
- // The last argument is valid because there are no special
- // operators yet, so it'll never get called
+ }, specialPicker, operators::get);
ITree<IDiceASTNode> tokenizedTree =
rawTokens.rebuildTree(DiceASTParser::convertLeafNode,
DiceASTParser::convertOperatorNode);
-
+
return tokenizedTree;
}
+ private static ITree<String>
+ parseCloseArray(Deque<ITree<String>> queuedTrees) {
+ IFunctionalList<ITree<String>> children = new FunctionalList<>();
+
+ while (shouldContinuePopping(queuedTrees)) {
+ children.add(queuedTrees.pop());
+ }
+
+ queuedTrees.pop();
+
+ children.reverse();
+
+ ITree<String> arrayTree = new Tree<>("[]", children);
+
+ return arrayTree;
+ }
+
+ private static boolean
+ shouldContinuePopping(Deque<ITree<String>> queuedTrees) {
+ String peekToken = queuedTrees.peek().getHead();
+
+ return !peekToken.equals("[");
+ }
+
private static boolean isOperatorNode(String token) {
+ if (StringUtils.containsOnly(token, "\\[")) {
+ return true;
+ } else if (StringUtils.containsOnly(token, "\\]")) {
+ return true;
+ }
+
+ if (token.equals("[]")) {
+ // This is a synthetic operator, constructed by [ and ]
+ return true;
+ }
+
try {
OperatorDiceNode.fromString(token);
return true;
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceSanitizer.java b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceSanitizer.java
index 05fddf6..6263ea9 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceSanitizer.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTReferenceSanitizer.java
@@ -3,6 +3,8 @@ package bjc.dicelang.ast;
import bjc.dicelang.ast.nodes.IDiceASTNode;
import bjc.dicelang.ast.nodes.OperatorDiceNode;
import bjc.dicelang.ast.nodes.VariableDiceNode;
+import bjc.utils.data.IHolder;
+import bjc.utils.data.Identity;
import bjc.utils.funcdata.IFunctionalMap;
import bjc.utils.funcdata.ITree;
import bjc.utils.funcdata.TopDownTransformResult;
@@ -41,6 +43,7 @@ public class DiceASTReferenceSanitizer {
switch (((OperatorDiceNode) node)) {
case ASSIGN:
return TopDownTransformResult.TRANSFORM;
+ case ARRAY:
case LET:
return TopDownTransformResult.PASSTHROUGH;
case ADD:
@@ -60,28 +63,134 @@ public class DiceASTReferenceSanitizer {
throw new UnsupportedOperationException(
"Assignment must have two arguments.");
}
-
+
ITree<IDiceASTNode> nameTree = ast.getChild(0);
ITree<IDiceASTNode> valueTree = ast.getChild(1);
if (!DiceASTUtils.containsSimpleVariable(nameTree)) {
- throw new UnsupportedOperationException(
- "Assignment must be between a variable and a expression");
+ if (nameTree.getHead() == OperatorDiceNode.ARRAY) {
+ IHolder<Boolean> allSimpleVariables = new Identity<>(true);
+
+ nameTree.doForChildren((child) -> {
+ if (allSimpleVariables.getValue()) {
+ boolean isSimple =
+ DiceASTUtils.containsSimpleVariable(child);
+
+ allSimpleVariables.replace(isSimple);
+ }
+ });
+
+ if (!allSimpleVariables.getValue()) {
+ throw new UnsupportedOperationException(
+ "Array assignment must be between variables and"
+ + " a expression/array of expressions");
+ }
+
+ if (valueTree.getHead() == OperatorDiceNode.ARRAY) {
+ if (nameTree.getChildrenCount() != valueTree
+ .getChildrenCount()) {
+ throw new UnsupportedOperationException(
+ "Array assignment between arrays must be"
+ + " between two arrays of equal length");
+ }
+ }
+ } else {
+ throw new UnsupportedOperationException(
+ "Assignment must be between a variable and a expression");
+ }
+ }
+
+ if (nameTree.getHead() == OperatorDiceNode.ARRAY) {
+ if (valueTree.getHead() == OperatorDiceNode.ARRAY) {
+ IHolder<Integer> childCounter = new Identity<>(0);
+
+ ITree<IDiceASTNode> returnTree =
+ new Tree<>(OperatorDiceNode.ARRAY);
+
+ nameTree.doForChildren((child) -> {
+ String variableName = child.transformHead((node) -> {
+ return ((VariableDiceNode) node).getVariable();
+ });
+
+ ITree<IDiceASTNode> currentValue =
+ valueTree.getChild(childCounter.getValue());
+
+ ITree<IDiceASTNode> sanitizedSubtree =
+ doSingleSanitize(ast, enviroment, child,
+ currentValue, variableName);
+
+ if (sanitizedSubtree == null) {
+ ITree<IDiceASTNode> oldTree = new Tree<>(
+ ast.getHead(), child, currentValue);
+
+ returnTree.addChild(oldTree);
+ } else {
+ returnTree.addChild(sanitizedSubtree);
+ }
+
+ childCounter.transform((count) -> count + 1);
+ });
+
+ return returnTree;
+ }
+
+ ITree<IDiceASTNode> returnTree =
+ new Tree<>(OperatorDiceNode.ARRAY);
+
+ nameTree.doForChildren((child) -> {
+ String variableName = child.transformHead(
+ (node) -> ((VariableDiceNode) node).getVariable());
+
+ ITree<IDiceASTNode> sanitizedChild = doSingleSanitize(ast,
+ enviroment, child, valueTree, variableName);
+ if (sanitizedChild == null) {
+ ITree<IDiceASTNode> oldTree =
+ new Tree<>(ast.getHead(), child, valueTree);
+
+ returnTree.addChild(oldTree);
+ } else {
+ returnTree.addChild(sanitizedChild);
+ }
+ });
+
+ return returnTree;
}
String variableName = nameTree.transformHead(
(node) -> ((VariableDiceNode) node).getVariable());
+ ITree<IDiceASTNode> sanitizedTree = doSingleSanitize(ast,
+ enviroment, nameTree, valueTree, variableName);
+
+ if (sanitizedTree == null) {
+ return ast;
+ }
+
+ return sanitizedTree;
+ }
+
+ private static ITree<IDiceASTNode> doSingleSanitize(
+ ITree<IDiceASTNode> ast,
+ IFunctionalMap<String, ITree<IDiceASTNode>> enviroment,
+ ITree<IDiceASTNode> nameTree, ITree<IDiceASTNode> valueTree,
+ String variableName) {
if (enviroment.containsKey(variableName)) {
+ // @ is a meta-variable standing for the left side of an
+ // assignment
+ enviroment.put("@", enviroment.get(variableName));
+
// We should always inline out references to last, because it
// will always change
ITree<IDiceASTNode> inlinedValue =
DiceASTInliner.selectiveInline(valueTree, enviroment,
- variableName, "last");
+ variableName, "last", "@");
+
+ // Remove temporary meta-variable
+ enviroment.remove("@");
return new Tree<>(ast.getHead(), nameTree, inlinedValue);
}
- return ast;
+ return null;
}
}
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java b/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java
index 10df77b..8fd066d 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/IOperatorCollapser.java
@@ -14,7 +14,7 @@ import bjc.utils.funcdata.ITree;
*
*/
public interface IOperatorCollapser extends
- Function<IFunctionalList<IPair<Integer, ITree<IDiceASTNode>>>,
- IPair<Integer, ITree<IDiceASTNode>>> {
+ Function<IFunctionalList<IPair<IResult, ITree<IDiceASTNode>>>,
+ IPair<IResult, ITree<IDiceASTNode>>> {
// Just an alias
}
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/IResult.java b/dice-lang/src/main/java/bjc/dicelang/ast/IResult.java
new file mode 100644
index 0000000..9a3f325
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/IResult.java
@@ -0,0 +1,16 @@
+package bjc.dicelang.ast;
+
+/**
+ * Represents a result from an expression evaluation
+ *
+ * @author ben
+ *
+ */
+public interface IResult {
+ /**
+ * Get the type of this result
+ *
+ * @return The type of this result
+ */
+ public ResultType getType();
+}
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/IntegerResult.java b/dice-lang/src/main/java/bjc/dicelang/ast/IntegerResult.java
new file mode 100644
index 0000000..c8d9a64
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/IntegerResult.java
@@ -0,0 +1,40 @@
+package bjc.dicelang.ast;
+
+/**
+ * Represents a integer-valued result
+ *
+ * @author ben
+ *
+ */
+public class IntegerResult implements IResult {
+ private int value;
+
+ /**
+ * Create a new integer valued result
+ *
+ * @param val
+ * The value of the result
+ */
+ public IntegerResult(int val) {
+ value = val;
+ }
+
+ /**
+ * Get the value of this result
+ *
+ * @return The value of this result
+ */
+ public int getValue() {
+ return value;
+ }
+
+ @Override
+ public ResultType getType() {
+ return ResultType.INTEGER;
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(value);
+ }
+}
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/ResultType.java b/dice-lang/src/main/java/bjc/dicelang/ast/ResultType.java
new file mode 100644
index 0000000..d5e94b9
--- /dev/null
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/ResultType.java
@@ -0,0 +1,18 @@
+package bjc.dicelang.ast;
+
+/**
+ * Represents the result of a computation
+ *
+ * @author ben
+ *
+ */
+public enum ResultType {
+ /**
+ * Represents a result that is equivalent to a single integer
+ */
+ INTEGER,
+ /**
+ * Represents a result that is an array
+ */
+ ARRAY;
+}
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java
index c0f7bd3..18df122 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/nodes/OperatorDiceNode.java
@@ -34,6 +34,10 @@ public enum OperatorDiceNode implements IDiceASTNode {
*/
GROUP(DICE),
/**
+ * Represents constructing an array from a sequence of expressions
+ */
+ ARRAY(EXPRESSION),
+ /**
* Represents assigning one node to another
*/
ASSIGN(EXPRESSION),
@@ -79,6 +83,8 @@ public enum OperatorDiceNode implements IDiceASTNode {
return COMPOUND;
case "=>":
return LET;
+ case "[]":
+ return ARRAY;
default:
throw new IllegalArgumentException(
s + " is not a valid operator node");
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/optimization/ConstantCollapser.java b/dice-lang/src/main/java/bjc/dicelang/ast/optimization/ConstantCollapser.java
index e476d74..7b746ac 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/optimization/ConstantCollapser.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/optimization/ConstantCollapser.java
@@ -77,6 +77,12 @@ public class ConstantCollapser implements IOptimizationPass {
}
return new Tree<>(operator, children);
+ case ARRAY:
+ if (children.getSize() != 1) {
+ return new Tree<>(operator, children);
+ }
+
+ return children.first();
case ASSIGN:
case LET:
default:
diff --git a/dice-lang/src/main/java/bjc/dicelang/ast/optimization/OperationCondenser.java b/dice-lang/src/main/java/bjc/dicelang/ast/optimization/OperationCondenser.java
index f41a3ef..3988d2a 100644
--- a/dice-lang/src/main/java/bjc/dicelang/ast/optimization/OperationCondenser.java
+++ b/dice-lang/src/main/java/bjc/dicelang/ast/optimization/OperationCondenser.java
@@ -51,6 +51,7 @@ public class OperationCondenser {
case DIVIDE:
case COMPOUND:
return TopDownTransformResult.PUSHDOWN;
+ case ARRAY:
case ASSIGN:
case GROUP:
case LET: