summaryrefslogtreecommitdiff
path: root/dice-lang/src/main/java/bjc/dicelang/ast/ArithmeticCollapser.java
blob: 5c00fe263e25465d1fedcef87ae095f063f1fb19 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package bjc.dicelang.ast;

import java.util.function.BinaryOperator;

import bjc.dicelang.ast.nodes.IDiceASTNode;
import bjc.dicelang.ast.nodes.OperatorDiceNode;
import bjc.utils.data.IPair;
import bjc.utils.data.Pair;
import bjc.utils.funcdata.IFunctionalList;
import bjc.utils.funcdata.ITree;
import bjc.utils.funcdata.Tree;

/**
 * Responsible for collapsing arithmetic operators
 * 
 * @author ben
 *
 */
final class ArithmeticCollapser implements IOperatorCollapser {
	private OperatorDiceNode		type;

	private BinaryOperator<Integer>	valueOp;

	public ArithmeticCollapser(OperatorDiceNode type,
			BinaryOperator<Integer> valueOp) {
		this.type = type;
		this.valueOp = valueOp;
	}

	@Override
	public IPair<Integer, ITree<IDiceASTNode>> apply(
			IFunctionalList<IPair<Integer, ITree<IDiceASTNode>>> nodes) {
		IPair<Integer, ITree<IDiceASTNode>> initState =
				new Pair<>(0, new Tree<>(type));

		BinaryOperator<IPair<Integer, ITree<IDiceASTNode>>> reducer =
				(currentState, accumulatedState) -> {
					// Force evaluation of accumulated state to prevent
					// certain bugs from occuring
					accumulatedState.merge((l, r) -> null);

					return reduceStates(accumulatedState, currentState);
				};

		IPair<Integer, 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) {
		return accumulatedState
				.bind((accumulatedValue, accumulatedTree) -> {
					return currentState
							.bind((currentValue, currentTree) -> {
								accumulatedTree.addChild(currentTree);

								Integer combinedValue = valueOp.apply(
										accumulatedValue, currentValue);

								return new Pair<>(combinedValue,
										accumulatedTree);
							});
				});
	}
}