package com.multitude.bless; //BAST.java //BLESS Abstract Syntax Tree //by extending ASTImpl, BAST looks like an EMF object //by implementing Tree, BAST is produced by ANTLR v3 parser import org.antlr.runtime.tree.Tree; import org.antlr.runtime.Token; import org.eclipse.emf.common.util.EList; import blessModel.AST; import blessModel.impl.ASTImpl; import edu.cmu.sei.aadl.model.core.AObject; /** * * BLESS Abstract Syntax Tree: By extending ASTImpl, * BAST looks like an EMF object. By implementing Tree, BAST is produced by * ANTLR v3 parser. * * @author brl * */ public class BAST extends ASTImpl implements Tree { /** A single token is the payload */ public Token token; /** * What token indexes bracket all tokens associated with this node and below? */ protected int startIndex = -1, stopIndex = -1; /** Who is the parent node of this node; if null, implies node is root */ public BAST parent; /** What index is this node in the child list? Range: 0..n-1 */ public int childIndex = -1; /** reference to the AADL object with the name of this token's text. */ public AObject reference = null; /** A Tree holding a token that is invalid. */ public static final Tree INVALID_NODE = new BAST(Token.INVALID_TOKEN); public BAST() { super(); } /** * Constructor from another tree node does not copy EList child */ public BAST(BAST node) { super(); this.token = node.token; this.startIndex = node.startIndex; this.stopIndex = node.stopIndex; } /** Constructor from a token */ public BAST(Token t) { this.token = t; } /** * Add t as child of this node. * * Warning: if t has no children, but child does and child isNil then this * routine moves children to t via t.children = child.children; i.e., without * copying the array. */ public void addChild(Tree arg0) { // System.out.println("add child "+t.toStringTree()+" // "+this.toStringTree()); // System.out.println("existing children: "+children); if (arg0 == null) { return; // do nothing upon addChild(null) } BAST childTree = (BAST) arg0; EList children = getChild(); if (childTree.isNil()) { // t is an empty node possibly with children if (children != null && children == childTree.getChild()) { throw new RuntimeException("attempt to add child list to itself"); } // just add all of childTree's children to this if (childTree.getChild() != null) { if (children != null) { // must copy, this has children already int n = childTree.getChild().size(); for (int i = 0; i < n; i++) { BAST c = (BAST) childTree.getChild().get(i); children.add(c); // handle double-link stuff for each child of nil root c.setParent(this); c.setChildIndex(children.size() - 1); } } else { // no children for this but t has children; just set pointer // call general freshener routine this.child = childTree.getChild(); this.freshenParentAndChildIndexes(); } } } else { // child is not nil (don't care about children) if (children == null) { throw new RuntimeException("EList child is null."); } children.add((BAST) arg0); childTree.setParent(this); childTree.setChildIndex(children.size() - 1); } // System.out.println("now children are: "+children); } // end of addChild public Object deleteChild(int i) { EList children = getChild(); if (children == null) { return null; } BAST disowned = (BAST) children.remove(i); // walk rest and decrement their child indexes this.freshenParentAndChildIndexes(i); return disowned; } // end of deleteChild public Tree dupNode() { return new BAST(this); } public Tree dupTree() { BAST newTree = new BAST(this); // duplicate everything in EList child if (getChildCount() > 0) for (int i = 0; i < getChildCount(); i++) newTree.addChild(((BAST) getChild(i)).dupTree()); return newTree; } public int getCharPositionInLine() { if (token == null || token.getCharPositionInLine() == -1) { if (getChildCount() > 0) { return getChild(0).getCharPositionInLine(); } return 0; } return token.getCharPositionInLine(); } public Tree getChild(int i) { if (getChild() == null || i >= getChild().size()) { return null; } return (BAST) getChild().get(i); } public int getChildCount() { return getChild().size(); } public int getChildIndex() { return childIndex; } public int getLine() { if (token == null || token.getLine() == 0) { if (getChildCount() > 0) { return getChild(0).getLine(); } return 0; } return token.getLine(); } public Tree getParent() { return parent; } /** * Return token's text, if any. */ public String getText() { if (token == null) { return null; } return token.getText(); } /** * Returns token's staring index */ public int getTokenStartIndex() { if (startIndex == -1 && token != null) { return token.getTokenIndex(); } return startIndex; } /** * Returns token's ending index */ public int getTokenStopIndex() { if (stopIndex == -1 && token != null) { return token.getTokenIndex(); } return stopIndex; } /** * Return token's type */ public int getType() { if (token == null) { return Token.INVALID_TOKEN_TYPE; } return token.getType(); } /** * Is the token held in this tree node null? */ public boolean isNil() { return token == null; } /** * Delete children from start to stop and replace with t even if t is a list * (nil-root tree). num of children can increase or decrease. For huge child * lists, inserting children can force walking rest of children to set their * childindex; could be slow. */ public void replaceChildren(int startChildIndex, int stopChildIndex, Object t) { /* * System.out.println("replaceChildren "+startChildIndex+", "+stopChildIndex+ " * with "+((BaseTree)t).toStringTree()); * System.out.println("in="+toStringTree()); */ EList children = getChild(); if (children == null) { throw new IllegalArgumentException("indexes invalid; no children in list"); } int replacingHowMany = stopChildIndex - startChildIndex + 1; int replacingWithHowMany; BAST newTree = (BAST) t; EList newChildren = null; // normalize to a list of children to add: newChildren if (newTree.isNil()) { newChildren = newTree.getChild(); } else { newChildren = newTree.getChild(); newChildren.add(newTree); } replacingWithHowMany = newChildren.size(); int numNewChildren = newChildren.size(); int delta = replacingHowMany - replacingWithHowMany; // if same number of nodes, do direct replace if (delta == 0) { int j = 0; // index into new children for (int i = startChildIndex; i <= stopChildIndex; i++) { BAST child = (BAST) newChildren.get(j); children.set(i, child); child.setParent(this); child.setChildIndex(i); j++; } } else if (delta > 0) { // fewer new nodes than there were // set children and then delete extra for (int j = 0; j < numNewChildren; j++) { children.set(startChildIndex + j, newChildren.get(j)); } int indexToDelete = startChildIndex + numNewChildren; for (int c = indexToDelete; c <= stopChildIndex; c++) { // delete same index, shifting everybody down each time //BAST killed = (BAST) children.remove(indexToDelete); } freshenParentAndChildIndexes(startChildIndex); } else { // more new nodes than were there before // fill in as many children as we can (replacingHowMany) w/o moving data for (int j = 0; j < replacingHowMany; j++) { children.set(startChildIndex + j, newChildren.get(j)); } // int numToInsert = replacingWithHowMany - replacingHowMany; for (int j = replacingHowMany; j < replacingWithHowMany; j++) { children.add(startChildIndex + j, newChildren.get(j)); } freshenParentAndChildIndexes(startChildIndex); } // System.out.println("out="+toStringTree()); } // end of replaceChildren public void setAObjectReference(AObject ao) { reference = ao; } /** * Set ith child to t * * @param i * @param t */ public void setChild(int i, Tree t) { if (t == null) { return; } if (t.isNil()) { throw new IllegalArgumentException("Can't set single child to a list"); } EList children = getChild(); if (children == null) { throw new IllegalArgumentException("null EList from getChild()"); } children.set(i, (BAST) t); ((BAST) t).setParent(this); ((BAST) t).setChildIndex(i); } public void setTokenStartIndex(int index) { startIndex = index; } public void setTokenStopIndex(int index) { stopIndex = index; } public String toString() { if (isNil()) { return "nil"; } if (getType() == Token.INVALID_TOKEN_TYPE) { return ""; } if (token == null) { return null; } return token.getText(); } /** Print out a whole tree not just a node. */ public String toStringTree() { EList children = getChild(); if (children == null || children.size() == 0) { return this.toString(); } StringBuffer buf = new StringBuffer(); if (!isNil()) { buf.append("("); buf.append(this.toString()); buf.append(' '); } for (int i = 0; getChild() != null && i < getChild().size(); i++) { BAST t = (BAST) children.get(i); if (i > 0) { buf.append(' '); } buf.append(t.toStringTree()); } if (!isNil()) { buf.append(")"); } return buf.toString(); } public void setParent(Tree t) { this.parent = (BAST) t; } public void setChildIndex(int index) { this.childIndex = index; } /** Set the parent and child index values for all children of t */ public void freshenParentAndChildIndexes() { freshenParentAndChildIndexes(0); } /** * Re-compute parent and child indices starting at offset. * * @param offset */ public void freshenParentAndChildIndexes(int offset) { int n = getChildCount(); for (int c = offset; c < n; c++) { BAST thisChild = (BAST) getChild(c); thisChild.setChildIndex(c); thisChild.setParent(this); } } }