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
|
package bjc.dicelang.v1.ast;
import bjc.dicelang.v1.ast.nodes.DiceASTType;
import bjc.dicelang.v1.ast.nodes.IDiceASTNode;
import bjc.dicelang.v1.ast.nodes.VariableDiceNode;
import bjc.utils.data.ITree;
import bjc.utils.data.Tree;
import bjc.utils.funcdata.FunctionalList;
import bjc.utils.funcdata.IList;
import bjc.utils.funcdata.IMap;
/**
* Inline variables in a dice AST
*
* @author ben
*
*/
public class DiceASTInliner {
/**
* Inline all the variables in the AST
*
* @param ast
* The AST to inline variables into
* @param enviroment
* The enviroment to inline from
* @return The inlined AST
*/
public static ITree<IDiceASTNode> inlineAll(ITree<IDiceASTNode> ast,
IMap<String, ITree<IDiceASTNode>> enviroment) {
// Tell the compiler that the null is for the entire varargs
// parameter, not a single one with a null value
return selectiveInline(ast, enviroment, (String[]) null);
}
private static ITree<IDiceASTNode> inlineNode(IDiceASTNode node, IMap<String, ITree<IDiceASTNode>> enviroment,
boolean specificInline, IList<String> variableNames) {
// Only variables get inlined
if(node.getType() != DiceASTType.VARIABLE) return new Tree<>(node);
// Get the name of what we're inlining
String variableName = ((VariableDiceNode) node).getVariable();
// If we're inlining only certain variables, do so
if(specificInline) {
// Only inline the variable if we're supposed to
if(variableNames.contains(variableName)) {
// You can't inline non-existent variables
if(!enviroment.containsKey(variableName)) throw new UnsupportedOperationException(
"Attempted to inline non-existant variable " + variableName);
// Return the tree for the variable
return enviroment.get(variableName);
}
// We're not inlining this particular variable
return new Tree<>(node);
}
// You can't inline non-existent variables
if(!enviroment.containsKey(variableName)) throw new UnsupportedOperationException(
"Attempted to inline non-existant variable " + variableName);
// Return the tree for the variable
return enviroment.get(variableName);
}
/**
* Inline the specified variables in the AST
*
* @param ast
* The AST to inline variables into
* @param enviroment
* The enviroment to inline from
* @param variables
* The variables to inline
* @return The inlined AST
*/
public static ITree<IDiceASTNode> selectiveInline(ITree<IDiceASTNode> ast,
IMap<String, ITree<IDiceASTNode>> enviroment, IList<String> variables) {
// Inline the specified variables
return selectiveInline(ast, enviroment, variables.toArray(new String[0]));
}
/**
* Inline the specified variables in the AST
*
* @param ast
* The AST to inline variables into
* @param enviroment
* The enviroment to inline from
* @param variables
* The variables to inline
* @return The inlined AST
*/
public static ITree<IDiceASTNode> selectiveInline(ITree<IDiceASTNode> ast,
IMap<String, ITree<IDiceASTNode>> enviroment, String... variables) {
// If we're selectively inlining, do so
if(variables != null && variables.length > 0) {
IList<String> variableNames = new FunctionalList<>(variables);
// Selectively inline each tree node
return ast.flatMapTree((node) -> {
return inlineNode(node, enviroment, true, variableNames);
});
}
// Inline everything in each node
return ast.flatMapTree((node) -> {
return inlineNode(node, enviroment, false, null);
});
}
}
|