SequenceChecker.java
001 /**
002  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003  */
004 package net.sourceforge.pmd.lang.dfa;
005 
006 import java.util.ArrayList;
007 import java.util.List;
008 
009 
010 /**
011  @author raik
012  *         <p/>
013  *         Computes the first sequence in a list.
014  *         <p/>
015  *         e.g.
016  *         IF_START      0
017  *         WHILE_EXPR    1
018  *         WHILE_END    2
019  *         IF_END      3
020  *         <p/>
021  *         The first sequence is WHILE_EXPR und WHILE_END. It returns always the
022  *         first inner nested scope.
023  */
024 public class SequenceChecker {
025 
026     /*
027      * Element of logical structure of brace nodes.
028      * */
029     private static class Status {
030   public static final int ROOT = -1;
031 
032   private List<Status> nextSteps = new ArrayList<Status>();
033   private int type;
034   private boolean lastStep;
035 
036   public Status(int type) {
037       this(type, false);
038   }
039 
040   public Status(int type, boolean lastStep) {
041       this.type = type;
042       this.lastStep = lastStep;
043   }
044 
045   public void addStep(Status type) {
046       nextSteps.add(type);
047   }
048 
049   public Status step(int type) {
050       for (int i = 0; i < this.nextSteps.size(); i++) {
051     if (type == nextSteps.get(i).type) {
052         return nextSteps.get(i);
053     }
054       }
055       return null;
056   }
057 
058   public boolean isLastStep() {
059       return this.lastStep;
060   }
061 
062   public boolean hasMoreSteps() {
063       return this.nextSteps.size() 1;
064   }
065     }
066 
067     private static Status root;
068 
069     static {
070   root = new Status(Status.ROOT);
071   Status ifNode = new Status(NodeType.IF_EXPR);
072   Status ifSt = new Status(NodeType.IF_LAST_STATEMENT);
073   Status ifStWithoutElse = new Status(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, true);
074   Status elseSt = new Status(NodeType.ELSE_LAST_STATEMENT, true);
075   Status whileNode = new Status(NodeType.WHILE_EXPR);
076   Status whileSt = new Status(NodeType.WHILE_LAST_STATEMENT, true);
077   Status switchNode = new Status(NodeType.SWITCH_START);
078   Status caseSt = new Status(NodeType.CASE_LAST_STATEMENT);
079   Status switchDefault = new Status(NodeType.SWITCH_LAST_DEFAULT_STATEMENT);
080   Status switchEnd = new Status(NodeType.SWITCH_END, true);
081 
082   Status forInit = new Status(NodeType.FOR_INIT);
083   Status forExpr = new Status(NodeType.FOR_EXPR);
084   Status forUpdate = new Status(NodeType.FOR_UPDATE);
085   Status forSt = new Status(NodeType.FOR_BEFORE_FIRST_STATEMENT);
086   Status forEnd = new Status(NodeType.FOR_END, true);
087 
088   Status doSt = new Status(NodeType.DO_BEFORE_FIRST_STATEMENT);
089   Status doExpr = new Status(NodeType.DO_EXPR, true);
090 
091   Status labelNode = new Status(NodeType.LABEL_STATEMENT);
092   Status labelEnd = new Status(NodeType.LABEL_LAST_STATEMENT, true);
093 
094   root.addStep(ifNode);
095   root.addStep(whileNode);
096   root.addStep(switchNode);
097   root.addStep(forInit);
098   root.addStep(forExpr);
099   root.addStep(forUpdate);
100   root.addStep(forSt);
101   root.addStep(doSt);
102   root.addStep(labelNode);
103 
104   ifNode.addStep(ifSt);
105   ifNode.addStep(ifStWithoutElse);
106   ifSt.addStep(elseSt);
107   ifStWithoutElse.addStep(root);
108   elseSt.addStep(root);
109 
110   labelNode.addStep(labelEnd);
111   labelEnd.addStep(root);
112 
113   whileNode.addStep(whileSt);
114   whileSt.addStep(root);
115 
116   switchNode.addStep(caseSt);
117   switchNode.addStep(switchDefault);
118   switchNode.addStep(switchEnd);
119   caseSt.addStep(caseSt);
120   caseSt.addStep(switchDefault);
121   caseSt.addStep(switchEnd);
122   switchDefault.addStep(switchEnd);
123   switchDefault.addStep(caseSt);
124   switchEnd.addStep(root);
125 
126   forInit.addStep(forExpr);
127   forInit.addStep(forUpdate);
128   forInit.addStep(forSt);
129   forExpr.addStep(forUpdate);
130   forExpr.addStep(forSt);
131   forUpdate.addStep(forSt);
132   forSt.addStep(forEnd);
133   forEnd.addStep(root);
134 
135   doSt.addStep(doExpr);
136   doExpr.addStep(root);
137     }
138 
139     private Status aktStatus;
140     private List<StackObject> bracesList;
141 
142     private int firstIndex = -1;
143     private int lastIndex = -1;
144 
145     /*
146      * Defines the logical structure.
147      * */
148     public SequenceChecker(List<StackObject> bracesList) {
149   this.aktStatus = root;
150   this.bracesList = bracesList;
151     }
152 
153     /**
154      * Finds the first most inner sequence e.g IFStart & IFEnd. If no sequence
155      * is found or the list is empty the method returns false.
156      */
157     public boolean run() {
158   this.aktStatus = root;
159   this.firstIndex = 0;
160   this.lastIndex = 0;
161   boolean lookAhead = false;
162 
163   for (int i = 0; i < this.bracesList.size(); i++) {
164       StackObject so = bracesList.get(i);
165       aktStatus = this.aktStatus.step(so.getType());
166 
167       if (aktStatus == null) {
168     if (lookAhead) {
169         this.lastIndex = i - 1;
170         return false;
171     }
172     this.aktStatus = root;
173     this.firstIndex = i;
174     i--;
175     continue;
176       else {
177     if (aktStatus.isLastStep() && !aktStatus.hasMoreSteps()) {
178         this.lastIndex = i;
179         return false;
180     else if (aktStatus.isLastStep() && aktStatus.hasMoreSteps()) {
181         lookAhead = true;
182         this.lastIndex = i;
183     }
184       }
185   }
186   return this.firstIndex == this.lastIndex;
187     }
188 
189     public int getFirstIndex() {
190   return this.firstIndex;
191     }
192 
193     public int getLastIndex() {
194   return this.lastIndex;
195     }
196 
197 }