summaryrefslogtreecommitdiff
path: root/dice-lang/src/main/java/bjc/dicelang/ast/DiceASTFreezer.java
blob: bad24f89dc4c9c5e45bbe1eae2bc97ad6c48773b (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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package bjc.dicelang.ast;

import java.util.function.Function;

import bjc.utils.funcdata.FunctionalList;
import bjc.utils.funcdata.FunctionalMap;
import bjc.utils.parserutils.AST;

/**
 * Freeze references in a dice AST, replacing variable references with what
 * the variables refer to
 * 
 * @author ben
 *
 */
public class DiceASTFreezer {
	private static class NodeFreezer
			implements Function<IDiceASTNode, AST<IDiceASTNode>> {
		private FunctionalMap<String, AST<IDiceASTNode>> enviroment;

		public NodeFreezer(FunctionalMap<String, AST<IDiceASTNode>> env) {
			enviroment = env;
		}

		@Override
		public AST<IDiceASTNode> apply(IDiceASTNode nod) {
			if (nod.getType() == DiceASTType.VARIABLE) {
				return expandNode((VariableDiceNode) nod);
			} else {
				return new AST<>(nod);
			}
		}

		protected AST<IDiceASTNode>
				expandNode(VariableDiceNode variableNode) {
			String varName = variableNode.getVariable();

			if (!enviroment.containsKey(varName)) {
				throw new IllegalArgumentException(
						"Attempted to freeze reference"
								+ " to an undefined variable " + varName);
			}

			return enviroment.get(varName);
		}
	}

	private static final class SelectiveFreezer extends NodeFreezer {

		private FunctionalList<String> variableNames;

		public SelectiveFreezer(
				FunctionalMap<String, AST<IDiceASTNode>> env,
				FunctionalList<String> varNames) {
			super(env);
			variableNames = varNames;
		}

		@Override
		protected AST<IDiceASTNode>
				expandNode(VariableDiceNode variableNode) {
			if (variableNames.contains(variableNode.getVariable())) {
				return super.expandNode(variableNode);
			} else {
				return new AST<>(variableNode);
			}
		}
	}

	/**
	 * Freeze the references in an AST
	 * 
	 * @param tree
	 *            The tree to freeze references in
	 * @param env
	 *            The enviroment to get reference values from
	 * @return The tree with references frozen
	 */
	public static AST<IDiceASTNode> freezeAST(AST<IDiceASTNode> tree,
			FunctionalMap<String, AST<IDiceASTNode>> env) {
		return selectiveFreeze(tree, env);
	}

	/**
	 * Freeze the references in an expression backed by an AST
	 * 
	 * @param tree
	 *            The tree-backed expression to freeze references in
	 * @param env
	 *            The enviroment to get reference values from
	 * @return The tree with references frozen
	 */
	public static AST<IDiceASTNode> freezeAST(DiceASTExpression tree,
			FunctionalMap<String, DiceASTExpression> env) {
		return freezeAST(tree.getAst(),
				env.mapValues(expression -> expression.getAst()));
	}

	/**
	 * Freeze references to specified variables
	 * 
	 * @param tree
	 *            The tree-backed expression to freeze references in
	 * @param env
	 *            The enviroment to resolve variables against
	 * @param varNames
	 *            The names of the variables to freeze
	 * @return An AST with the specified variables frozen
	 */
	public static AST<IDiceASTNode> selectiveFreeze(AST<IDiceASTNode> tree,
			FunctionalMap<String, AST<IDiceASTNode>> env,
			String... varNames) {
		return selectiveFreeze(tree, env, new FunctionalList<>(varNames));
	}

	/**
	 * Freeze references to specified variables
	 * 
	 * @param tree
	 *            The tree-backed expression to freeze references in
	 * @param env
	 *            The enviroment to resolve variables against
	 * @param varNames
	 *            The names of the variables to freeze
	 * @return An AST with the specified variables frozen
	 */
	public static AST<IDiceASTNode> selectiveFreeze(AST<IDiceASTNode> tree,
			FunctionalMap<String, AST<IDiceASTNode>> env,
			FunctionalList<String> varNames) {
		return tree.expand(new SelectiveFreezer(env, varNames));
	}
}