-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathInheritanceTreeManager.java
327 lines (261 loc) · 9.45 KB
/
InheritanceTreeManager.java
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
package qimpp;
import xtc.tree.GNode;
import xtc.tree.Node;
import xtc.tree.Visitor;
import xtc.tree.Printer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Arrays;
/** Maintains a tree with pointers class definitions for all classes referenced in the program being translated
*
* @author QIMPP
* */
public class InheritanceTreeManager {
///////////////////
// STRING CONSTANTS
///////////////////
/* TODO: Implement package-based dereferencing: right now we're just naively looking by name */
/** Maps class names to their class tree nodes */
HashMap<String, GNode> classNameMap;
/** Root of the package/class tree */
GNode root;
/** The class everyone inherits from (Object) */
GNode rootClassNode;
//////////////////
// STATE VARIABLES
//////////////////
public static final String CLASS_TREE_NODE = "ClassTreeNode";
public static final String PACKAGE_QUALIFIER = "PackageQualifier";
public static final String CLASS_STRUCTURE_ROOT = "ClassStructureRoot";
public static final String QUALIFIER_NAME = "QualifierName";
public static final String CLASS_NAME = "ClassName";
public static final String CLASS_DECLARATION = "ClassDeclaration";
public static final String PARENT_CLASS = "ParentClass";
/** The package of the sourc
GNode currentNamespace;);
GNode javaLangNamespace;
G
/** Construct the tree with the given root object node (java.lang.Object)
*
* @param rootClass The fully qualified name of the root class ({"java", "lang", "Object"})
* @param rootClassDeclaration the ClassDeclaration of the root class containing its fields and methods
* */
public InheritanceTreeManager(ArrayList<String> rootClass, GNode rootClassDeclaration){
////
root = GNode.create(CLASS_STRUCTURE_ROOT);
GNode rootClassTreeNode = GNode.create(CLASS_TREE_NODE);
rootClassTreeNode.setProperty("ClassName", "Object");;
rootClassTreeNode.setProperty("ClassDeclaration", rootClassDeclaration);
// Set a direct reference to what everyone inherits from
this.rootClassNode = rootClassTreeNode;
this.rootClassName = rootClass;
insertClass(rootClass, rootClassTreeNode);
}
private ArrayList<String> rootClassName;
/** An overload where java.lang.Object is implicit */
public InheritanceTreeManager(GNode rootClassDeclaration) {
this( new ArrayList<String>( Arrays.asList("java", "lang","Object")), rootClassDeclaration);
}
/** A toString using a Visitor for debugging */
public String toString(){
final StringBuilder b = new StringBuilder();
b.append("Class Inheritance Tree:\n");
new Visitor () {
public void visitPackageQualifier( GNode n ){
b.append("Package qualifier: " + n.getStringProperty(QUALIFIER_NAME) + "\n");
visit(n);
b.append("End " + n.getStringProperty(QUALIFIER_NAME) + "\n");
}
public void visitClassTreeNode( GNode n ){
b.append("ClassTreeNode: " + n.getStringProperty(CLASS_NAME) + "\n");
}
public void visit(Node n) {
for (Object o : n) if (o instanceof Node) dispatch((Node)o);
}
}.dispatch(root);
return b.toString();
}
//
// State variables for dereference()
//
/** The node found by dereference() */
private GNode foundNode;
/** The furthest we got dereferencing the node in the package tree
* */
private GNode deepestPackageNode;
/** Index of the qualifier we're up to */
private int dereferenceDepth;
/** Utility function to get the parent ClassTreeNode */
public GNode getParent( GNode classTreeNode ){
return (GNode)classTreeNode.getProperty(PARENT_CLASS);
}
/** Takes a class name and gets the fully qualified class name,
* or null if it cannot be found.
* *
* */
public ArrayList<String> disambiguate( String className ) {
return new ArrayList<String>(Arrays.asList(className.split("\\.")));
}
/** Figure out which class we're referring to, and get its
* ClassTreeNode to know its inheritance hierarchy */
public GNode getClassTreeNode(String className){
return dereference(disambiguate(className));
}
/**
* Utility function return the ClassDeclaration for a given name
* @return the ClassDeclaration GNode
*/
public GNode getClassDeclarationNode(String className) {
GNode classTreeNode = getClassTreeNode(className);
if (classTreeNode != null){
return (GNode)classTreeNode.getProperty(CLASS_DECLARATION);
}
return null;
}
/** An overload-alias to minimize necessary brain-space */
public GNode getClassTreeNode(ArrayList<String> className){
return dereference(className);
}
int deepestDereference;
/** Get the ClassNode based on its fully qualified package name
* Also sets deepestPackageNode
* */
public GNode dereference(final ArrayList<String> className){
// Traverse with state variables
//
//System.err.print("finding ");
for (String s: className){
//System.err.print(s);
}
//
foundNode = null;
dereferenceDepth = 0;
deepestDereference = 0;
deepestPackageNode = root;
new Visitor() {
public void visitClassTreeNode(GNode n){
if (dereferenceDepth >= className.size())
return;
if (
getClassTreeNodeName(n).equals
(className.get(dereferenceDepth))
){
//////
foundNode = n;
}
else {
//////
}
}
public void visitPackageQualifier(GNode n){
if (dereferenceDepth >= className.size())
return;
if (n.getStringProperty(QUALIFIER_NAME).equals(className.get(dereferenceDepth))) {
dereferenceDepth++;
if (dereferenceDepth > deepestDereference)
deepestDereference = dereferenceDepth;
deepestPackageNode = n;
visit(n);
dereferenceDepth--;
}
else {
//////
}
}
public void visit(Node n) {
for (Object o : n) if (o instanceof Node) dispatch((Node)o);
}
}.dispatch(root);
//////
return foundNode;
}
public void reparent(ArrayList<String> child, ArrayList<String> parent){
GNode childNode = dereference(child);
GNode parentNode = dereference(parent);
if ( null == childNode || null == parentNode ) {
throw new RuntimeException("Failed to reparent");
}
childNode.setProperty(PARENT_CLASS, parentNode);
}
private String getClassTreeNodeName(GNode n){
return n.getStringProperty(CLASS_NAME);
}
/** Gets an ordered list of the inheritance hierarchy for a class
*
* @param className an array of Strings defining the fully
* qualified name of the class we want
* For example, the array for Point in package org.xtc should be
* ["org", "xtc", "Point"]
* For Point in the root package (the "src" directory) should just
* be ["Point"]
* */
public ArrayList<GNode> getParentList(ArrayList<String> className){
return null;
}
/** Inserts a class into the tree and parents it to the given object
*
* @param className the fully-qualified name of the class to insert
* @param parentName the fully-qualified name of the class's
* parent, or null if it's Object
*
* @throws RuntimeException with the message
* "No such parent class [className]"
* */
public GNode insertClass(ArrayList<String> className, ArrayList<String> parentName, GNode classDeclaration){
GNode classTreeNode = GNode.create(CLASS_TREE_NODE);
if ( null == parentName ) {
// If the parent isn't specified, set it to Object
classTreeNode.setProperty("ParentClass", rootClassNode);
}
else{
GNode parent = dereference(parentName);
////
// If the parent doesn't exist, throw a runtime exception
if ( null == parent) {
String parentNameString = "";
for (int i = 0; i < parentName.size(); i++){
parentNameString += parentName.get(i) + ".";
}
throw new RuntimeException(
"No such parent class " +
parentName.get(parentName.size() - 1));
}
classTreeNode.setProperty("ParentClass", parent);
}
classTreeNode.setProperty(
"ClassName", className.get(className.size() - 1));
classTreeNode.setProperty("ClassDeclaration", classDeclaration);
insertClass(className, classTreeNode);
return classTreeNode;
}
/** Insert a tree node into the tree. Its name and parent should
* already be set
* @param className the fully qualified name of the node
* @param classTreeNode the node containing the classDefinition
* and a pointer to the parent of this object*/
private boolean insertClass(ArrayList<String> className, GNode classTreeNode){
// dereference sets deepestPackageNode
if ( null != dereference(className)){
// This class should not already be inserted!
////
return false;
}
else{
// Starting at the deepest already-defined point in the tree, make new entries
GNode n = deepestPackageNode;
////
GNode current = n;
for( int i = deepestDereference; i < className.size() - 1; i++ ){
GNode newQualifier = GNode.create(PACKAGE_QUALIFIER);
newQualifier.setProperty(QUALIFIER_NAME, className.get(i));
current.add(newQualifier);
////
current = newQualifier;
}
// Finally, add the actual class tree node
current.add(classTreeNode);
return true; //success
}
}
}