001package daikon.tools.jtb;
002
003import java.util.Enumeration;
004import jtb.syntaxtree.*;
005import jtb.visitor.*;
006
007/**
008 * OrigModifier is a visitor that places "orig()" around varible names and correspondingly corrects
009 * positioning fields of all the tokens in tree to accomodate the change. For example, the
010 * expression get(this.x) would be changed to get(orig(this.x)).
011 */
012public class OrigModifier extends DepthFirstVisitor {
013
014  private int columnshift = 0;
015  private int columnshiftline = -1;
016
017  // columnshifting only applies to a single line, then is turned off agian.
018  // States for the variables:
019  // columnshift == 0, columnshiftline == -1:
020  //    no column shifting needed
021  // columnshift != 0, columnshiftline != -1:
022  //    column shifting being needed, applies only to specified line
023
024  /**
025   * Corrects column fields of n.
026   *
027   * <p>Modifies: n, this.
028   */
029  @Override
030  public void visit(NodeToken n) {
031    if (n.beginLine == columnshiftline) {
032      n.beginColumn = n.beginColumn + columnshift;
033      n.endColumn = n.endColumn + columnshift;
034    } else {
035      columnshift = 0;
036      columnshiftline = -1;
037    }
038  }
039
040  /**
041   * Checks if n is a variable name. If so adds "orig(" to the front of the name and ")" to the end.
042   *
043   * <p>Modifies: n, this.
044   */
045  // f0 -> PrimaryPrefix()
046  // f1 -> ( PrimarySuffix() )*
047  @Override
048  @SuppressWarnings("JdkObsolete") // JTB Enumeration
049  public void visit(PrimaryExpression n) {
050    // let simple variables be variables with out "."'s in their names
051    // such as x or myList
052    // let compound variables be variables with "."'s in their names
053    // such as this.x or myPackage.MyObject.myList
054
055    // First checks for and handles simple variables.
056
057    // test if optional list length is zero, if not, then it is not
058    // the name of a simple variable
059    if (n.f1.size() == 0) {
060      // checks if the nodeChoice's choice is Name
061      if (n.f0.f0.choice instanceof Name) {
062        // checks if the Name is simple
063        if (((Name) n.f0.f0.choice).f1.size() == 0) {
064          NodeToken variableToken = ((Name) n.f0.f0.choice).f0;
065          variableToken.tokenImage = "orig(" + variableToken.tokenImage + ")";
066          columnshift = columnshift + 6;
067          columnshiftline = variableToken.endLine;
068          super.visit(n);
069
070          // Corrects for the fact that super.visit(n) incremented
071          // variableToken.beginColumn by 6 too much since the addition of
072          // "orig()" does not effect firstToken.beginColumn.
073          variableToken.beginColumn = variableToken.beginColumn - 6;
074          return;
075        }
076      }
077    }
078
079    if (n.f1.size() == 1) {
080      // System.out.println("if1");
081      if (n.f1.elementAt(0) instanceof PrimarySuffix) {
082        // System.out.println("if2");
083        if (((PrimarySuffix) n.f1.elementAt(0)).f0.choice instanceof NodeSequence) {
084          if (n.f0.f0.choice instanceof NodeToken) {
085            NodeToken firstToken = (NodeToken) n.f0.f0.choice;
086            firstToken.tokenImage = "orig(" + firstToken.tokenImage;
087            Enumeration<Node> nodeSequence =
088                ((NodeSequence) ((PrimarySuffix) n.f1.elementAt(0)).f0.choice).elements();
089            NodeToken lastToken = firstToken;
090            while (nodeSequence.hasMoreElements()) {
091              lastToken = (NodeToken) nodeSequence.nextElement();
092            }
093            lastToken.tokenImage = lastToken.tokenImage + ")";
094
095            // Updates columnshift for the addition of "orig(", the
096            // columnshift is updated for the addition of ")" after
097            // super.visit(n)
098            columnshift = columnshift + 5;
099            columnshiftline = firstToken.beginLine;
100            super.visit(n);
101
102            // Corrects for the fact that super.visit(n) incremented
103            // firstToken.beginColumn by 5 too much since the addition
104            // of "orig(" does not effect firstToken.beginColumn.
105            firstToken.beginColumn = firstToken.beginColumn - 5;
106
107            // since lastToken is the last node in the visiting order
108            // of n, all NodeToken effected by the addition of the
109            // ")" at the end of lastToken are visited after all the children
110            // of are visited.  Thus,super.visit(n) may be called before
111            // all code that corrects the column fields for the addition of
112            // ")".
113            columnshiftline = lastToken.endLine;
114            columnshift = columnshift + 1;
115            lastToken.endColumn = lastToken.endColumn + 1;
116            return;
117          }
118        }
119      }
120    }
121    super.visit(n);
122  }
123}