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 }
|