Mercurial > hg > truffle
comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java @ 17275:846c059e3ecf
Truffle: allow interface types in child fields
author | Andreas Woess <andreas.woess@jku.at> |
---|---|
date | Tue, 30 Sep 2014 23:42:08 +0200 |
parents | e52ad0d3b7d6 |
children | 5787218bad91 |
comparison
equal
deleted
inserted
replaced
17274:5c55441b4c62 | 17275:846c059e3ecf |
---|---|
183 return nodeClasses.get(clazz); | 183 return nodeClasses.get(clazz); |
184 } | 184 } |
185 | 185 |
186 public NodeClass(Class<? extends Node> clazz, FieldOffsetProvider fieldOffsetProvider) { | 186 public NodeClass(Class<? extends Node> clazz, FieldOffsetProvider fieldOffsetProvider) { |
187 List<NodeField> fieldsList = new ArrayList<>(); | 187 List<NodeField> fieldsList = new ArrayList<>(); |
188 List<Long> parentOffsetsList = new ArrayList<>(); | 188 long parentFieldOffset = -1; |
189 List<Long> childOffsetsList = new ArrayList<>(); | 189 List<Long> childOffsetsList = new ArrayList<>(); |
190 List<Long> childrenOffsetsList = new ArrayList<>(); | 190 List<Long> childrenOffsetsList = new ArrayList<>(); |
191 | 191 |
192 for (Field field : getAllFields(clazz)) { | 192 for (Field field : getAllFields(clazz)) { |
193 if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) { | 193 if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) { |
194 continue; | 194 continue; |
195 } | 195 } |
196 | 196 |
197 NodeFieldKind kind; | 197 NodeFieldKind kind; |
198 if (Node.class.isAssignableFrom(field.getType()) && field.getName().equals("parent") && field.getDeclaringClass() == Node.class) { | 198 if (field.getDeclaringClass() == Node.class && field.getName().equals("parent")) { |
199 assert Node.class.isAssignableFrom(field.getType()); | |
199 kind = NodeFieldKind.PARENT; | 200 kind = NodeFieldKind.PARENT; |
200 parentOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); | 201 parentFieldOffset = fieldOffsetProvider.objectFieldOffset(field); |
201 } else if (Node.class.isAssignableFrom(field.getType()) && field.getAnnotation(Child.class) != null) { | 202 } else if (field.getAnnotation(Child.class) != null) { |
203 checkChildField(field); | |
202 kind = NodeFieldKind.CHILD; | 204 kind = NodeFieldKind.CHILD; |
203 childOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); | 205 childOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); |
204 assert !Modifier.isFinal(field.getModifiers()) : "child field must not be final (\"" + field.getName() + "\", " + clazz + ")"; | 206 } else if (field.getAnnotation(Children.class) != null) { |
205 } else if (field.getType().isArray() && Node.class.isAssignableFrom(field.getType().getComponentType()) && field.getAnnotation(Children.class) != null) { | 207 checkChildrenField(field); |
206 kind = NodeFieldKind.CHILDREN; | 208 kind = NodeFieldKind.CHILDREN; |
207 childrenOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); | 209 childrenOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); |
208 assert Modifier.isFinal(field.getModifiers()) : "children array field must be final (\"" + field.getName() + "\", " + clazz + ")"; | |
209 } else { | 210 } else { |
210 kind = NodeFieldKind.DATA; | 211 kind = NodeFieldKind.DATA; |
211 } | 212 } |
212 fieldsList.add(new NodeField(kind, field.getType(), field.getName(), fieldOffsetProvider.objectFieldOffset(field))); | 213 fieldsList.add(new NodeField(kind, field.getType(), field.getName(), fieldOffsetProvider.objectFieldOffset(field))); |
213 } | 214 } |
215 | |
216 if (parentFieldOffset < 0) { | |
217 throw new AssertionError("parent field not found"); | |
218 } | |
219 | |
214 this.fields = fieldsList.toArray(new NodeField[fieldsList.size()]); | 220 this.fields = fieldsList.toArray(new NodeField[fieldsList.size()]); |
215 assert parentOffsetsList.size() == 1 : "must have exactly one parent field"; | 221 this.parentOffset = parentFieldOffset; |
216 this.parentOffset = parentOffsetsList.get(0); | |
217 this.childOffsets = toLongArray(childOffsetsList); | 222 this.childOffsets = toLongArray(childOffsetsList); |
218 this.childrenOffsets = toLongArray(childrenOffsetsList); | 223 this.childrenOffsets = toLongArray(childrenOffsetsList); |
219 this.clazz = clazz; | 224 this.clazz = clazz; |
225 } | |
226 | |
227 private static void checkChildField(Field field) { | |
228 if (!(Node.class.isAssignableFrom(field.getType()) || field.getType().isInterface())) { | |
229 throw new AssertionError("@Child field type must be a subclass of Node or an interface (" + field + ")"); | |
230 } | |
231 if (Modifier.isFinal(field.getModifiers())) { | |
232 throw new AssertionError("@Child field must not be final (" + field + ")"); | |
233 } | |
234 } | |
235 | |
236 private static void checkChildrenField(Field field) { | |
237 if (!(field.getType().isArray() && (Node.class.isAssignableFrom(field.getType().getComponentType()) || field.getType().getComponentType().isInterface()))) { | |
238 throw new AssertionError("@Children field type must be an array of a subclass of Node or an interface (" + field + ")"); | |
239 } | |
240 if (!Modifier.isFinal(field.getModifiers())) { | |
241 throw new AssertionError("@Children field must be final (" + field + ")"); | |
242 } | |
220 } | 243 } |
221 | 244 |
222 public NodeField[] getFields() { | 245 public NodeField[] getFields() { |
223 return fields; | 246 return fields; |
224 } | 247 } |
267 } | 290 } |
268 | 291 |
269 private int childrenCount() { | 292 private int childrenCount() { |
270 int nodeCount = childOffsets.length; | 293 int nodeCount = childOffsets.length; |
271 for (long fieldOffset : childrenOffsets) { | 294 for (long fieldOffset : childrenOffsets) { |
272 Node[] children = ((Node[]) unsafe.getObject(node, fieldOffset)); | 295 Object[] children = ((Object[]) unsafe.getObject(node, fieldOffset)); |
273 if (children != null) { | 296 if (children != null) { |
274 nodeCount += children.length; | 297 nodeCount += children.length; |
275 } | 298 } |
276 } | 299 } |
277 return nodeCount; | 300 return nodeCount; |
281 int nodeCount = childOffsets.length; | 304 int nodeCount = childOffsets.length; |
282 if (idx < nodeCount) { | 305 if (idx < nodeCount) { |
283 return (Node) unsafe.getObject(node, childOffsets[idx]); | 306 return (Node) unsafe.getObject(node, childOffsets[idx]); |
284 } else { | 307 } else { |
285 for (long fieldOffset : childrenOffsets) { | 308 for (long fieldOffset : childrenOffsets) { |
286 Node[] nodeArray = (Node[]) unsafe.getObject(node, fieldOffset); | 309 Object[] nodeArray = (Object[]) unsafe.getObject(node, fieldOffset); |
287 if (idx < nodeCount + nodeArray.length) { | 310 if (idx < nodeCount + nodeArray.length) { |
288 return nodeArray[idx - nodeCount]; | 311 return (Node) nodeArray[idx - nodeCount]; |
289 } | 312 } |
290 nodeCount += nodeArray.length; | 313 nodeCount += nodeArray.length; |
291 } | 314 } |
292 } | 315 } |
293 return null; | 316 return null; |
359 unsafe.putObject(clonedChild, nodeClass.parentOffset, clone); | 382 unsafe.putObject(clonedChild, nodeClass.parentOffset, clone); |
360 unsafe.putObject(clone, fieldOffset, clonedChild); | 383 unsafe.putObject(clone, fieldOffset, clonedChild); |
361 } | 384 } |
362 } | 385 } |
363 for (long fieldOffset : nodeClass.childrenOffsets) { | 386 for (long fieldOffset : nodeClass.childrenOffsets) { |
364 Node[] children = (Node[]) unsafe.getObject(orig, fieldOffset); | 387 Object[] children = (Object[]) unsafe.getObject(orig, fieldOffset); |
365 if (children != null) { | 388 if (children != null) { |
366 Node[] clonedChildren = (Node[]) Array.newInstance(children.getClass().getComponentType(), children.length); | 389 Object[] clonedChildren = (Object[]) Array.newInstance(children.getClass().getComponentType(), children.length); |
367 for (int i = 0; i < children.length; i++) { | 390 for (int i = 0; i < children.length; i++) { |
368 if (children[i] != null) { | 391 if (children[i] != null) { |
369 Node clonedChild = cloneNode(children[i]); | 392 Node clonedChild = cloneNode((Node) children[i]); |
370 clonedChildren[i] = clonedChild; | 393 clonedChildren[i] = clonedChild; |
371 unsafe.putObject(clonedChild, nodeClass.parentOffset, clone); | 394 unsafe.putObject(clonedChild, nodeClass.parentOffset, clone); |
372 } | 395 } |
373 } | 396 } |
374 unsafe.putObject(clone, fieldOffset, clonedChildren); | 397 unsafe.putObject(clone, fieldOffset, clonedChildren); |
386 if (child != null) { | 409 if (child != null) { |
387 nodes.add((Node) child); | 410 nodes.add((Node) child); |
388 } | 411 } |
389 } | 412 } |
390 for (long fieldOffset : nodeClass.childrenOffsets) { | 413 for (long fieldOffset : nodeClass.childrenOffsets) { |
391 Node[] children = (Node[]) unsafe.getObject(node, fieldOffset); | 414 Object[] children = (Object[]) unsafe.getObject(node, fieldOffset); |
392 if (children != null) { | 415 if (children != null) { |
393 for (Node child : children) { | 416 for (Object child : children) { |
394 if (child != null) { | 417 if (child != null) { |
395 nodes.add(child); | 418 nodes.add((Node) child); |
396 } | 419 } |
397 } | 420 } |
398 } | 421 } |
399 } | 422 } |
400 | 423 |
413 } | 436 } |
414 | 437 |
415 for (long fieldOffset : nodeClass.getChildrenOffsets()) { | 438 for (long fieldOffset : nodeClass.getChildrenOffsets()) { |
416 Object arrayObject = unsafe.getObject(parent, fieldOffset); | 439 Object arrayObject = unsafe.getObject(parent, fieldOffset); |
417 if (arrayObject != null) { | 440 if (arrayObject != null) { |
418 assert arrayObject instanceof Node[] : "Children array must be instanceof Node[] "; | 441 Object[] array = (Object[]) arrayObject; |
419 Node[] array = (Node[]) arrayObject; | |
420 for (int i = 0; i < array.length; i++) { | 442 for (int i = 0; i < array.length; i++) { |
421 if (array[i] == oldChild) { | 443 if (array[i] == oldChild) { |
422 assert assertAssignable(nodeClass, fieldOffset, newChild); | 444 assert assertAssignable(nodeClass, fieldOffset, newChild); |
423 array[i] = newChild; | 445 array[i] = newChild; |
424 return true; | 446 return true; |
653 p.print(" "); | 675 p.print(" "); |
654 } | 676 } |
655 if (parent == null) { | 677 if (parent == null) { |
656 p.println(nodeName(node)); | 678 p.println(nodeName(node)); |
657 } else { | 679 } else { |
658 String fieldName = "unknownField"; | 680 p.print(getNodeFieldName(parent, node, "unknownField")); |
659 NodeField[] fields = NodeClass.get(parent.getClass()).fields; | |
660 for (NodeField field : fields) { | |
661 Object value = field.loadValue(parent); | |
662 if (value == node) { | |
663 fieldName = field.getName(); | |
664 break; | |
665 } else if (value instanceof Node[]) { | |
666 int index = 0; | |
667 for (Node arrayNode : (Node[]) value) { | |
668 if (arrayNode == node) { | |
669 fieldName = field.getName() + "[" + index + "]"; | |
670 break; | |
671 } | |
672 index++; | |
673 } | |
674 } | |
675 } | |
676 p.print(fieldName); | |
677 p.print(" = "); | 681 p.print(" = "); |
678 p.println(nodeName(node)); | 682 p.println(nodeName(node)); |
679 } | 683 } |
680 | 684 |
681 for (Node child : node.getChildren()) { | 685 for (Node child : node.getChildren()) { |
711 for (int i = 0; i < level; i++) { | 715 for (int i = 0; i < level; i++) { |
712 sb.append("| "); | 716 sb.append("| "); |
713 } | 717 } |
714 | 718 |
715 if (parent != null) { | 719 if (parent != null) { |
716 String childName = ""; | 720 sb.append(getNodeFieldName(parent, node, "")); |
717 NodeField[] fields = NodeClass.get(parent.getClass()).fields; | |
718 for (NodeField field : fields) { | |
719 Object value = field.loadValue(parent); | |
720 if (value == node) { | |
721 childName = field.getName(); | |
722 break; | |
723 } else if (value instanceof Node[]) { | |
724 int index = 0; | |
725 for (Node arrayNode : (Node[]) value) { | |
726 if (arrayNode == node) { | |
727 childName = field.getName() + "[" + index + "]"; | |
728 break; | |
729 } | |
730 index++; | |
731 } | |
732 } | |
733 } | |
734 sb.append(childName); | |
735 } | 721 } |
736 | 722 |
737 sb.append(" (" + node.getClass().getSimpleName() + ") "); | 723 sb.append(" (" + node.getClass().getSimpleName() + ") "); |
738 sb.append(displaySourceAttribution(node)); | 724 sb.append(displaySourceAttribution(node)); |
739 p.println(sb.toString()); | 725 p.println(sb.toString()); |
740 | 726 |
741 for (Node child : node.getChildren()) { | 727 for (Node child : node.getChildren()) { |
742 printSourceAttributionTree(p, node, child, level + 1); | 728 printSourceAttributionTree(p, node, child, level + 1); |
743 } | 729 } |
744 p.flush(); | 730 p.flush(); |
731 } | |
732 | |
733 private static String getNodeFieldName(Node parent, Node node, String defaultName) { | |
734 NodeField[] fields = NodeClass.get(parent.getClass()).fields; | |
735 for (NodeField field : fields) { | |
736 Object value = field.loadValue(parent); | |
737 if (field.getKind() == NodeFieldKind.CHILD && value == node) { | |
738 return field.getName(); | |
739 } else if (field.getKind() == NodeFieldKind.CHILDREN) { | |
740 int index = 0; | |
741 for (Object arrayNode : (Object[]) value) { | |
742 if (arrayNode == node) { | |
743 return field.getName() + "[" + index + "]"; | |
744 } | |
745 index++; | |
746 } | |
747 } | |
748 } | |
749 return defaultName; | |
745 } | 750 } |
746 | 751 |
747 /** | 752 /** |
748 * Prints a human readable form of a {@link Node} AST to the given {@link PrintStream}. This | 753 * Prints a human readable form of a {@link Node} AST to the given {@link PrintStream}. This |
749 * print method does not check for cycles in the node structure. | 754 * print method does not check for cycles in the node structure. |
813 } | 818 } |
814 } | 819 } |
815 | 820 |
816 private static void printChildren(PrintWriter p, int level, Object value) { | 821 private static void printChildren(PrintWriter p, int level, Object value) { |
817 String sep; | 822 String sep; |
818 Node[] children = (Node[]) value; | 823 Object[] children = (Object[]) value; |
819 p.print(" = ["); | 824 p.print(" = ["); |
820 sep = ""; | 825 sep = ""; |
821 for (Node child : children) { | 826 for (Object child : children) { |
822 p.print(sep); | 827 p.print(sep); |
823 sep = ", "; | 828 sep = ", "; |
824 printTree(p, child, level + 1); | 829 printTree(p, (Node) child, level + 1); |
825 } | 830 } |
826 p.print("]"); | 831 p.print("]"); |
827 } | 832 } |
828 | 833 |
829 private static void printNewLine(PrintWriter p, int level) { | 834 private static void printNewLine(PrintWriter p, int level) { |