View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.dfa;
5   
6   import java.util.ArrayList;
7   import java.util.List;
8   
9   
10  /**
11   * @author raik
12   *         <p/>
13   *         Computes the first sequence in a list.
14   *         <p/>
15   *         e.g.
16   *         IF_START			0
17   *         WHILE_EXPR		1
18   *         WHILE_END		2
19   *         IF_END			3
20   *         <p/>
21   *         The first sequence is WHILE_EXPR und WHILE_END. It returns always the
22   *         first inner nested scope.
23   */
24  public class SequenceChecker {
25  
26      /*
27       * Element of logical structure of brace nodes.
28       * */
29      private static class Status {
30  	public static final int ROOT = -1;
31  
32  	private List<Status> nextSteps = new ArrayList<Status>();
33  	private int type;
34  	private boolean lastStep;
35  
36  	public Status(int type) {
37  	    this(type, false);
38  	}
39  
40  	public Status(int type, boolean lastStep) {
41  	    this.type = type;
42  	    this.lastStep = lastStep;
43  	}
44  
45  	public void addStep(Status type) {
46  	    nextSteps.add(type);
47  	}
48  
49  	public Status step(int type) {
50  	    for (int i = 0; i < this.nextSteps.size(); i++) {
51  		if (type == nextSteps.get(i).type) {
52  		    return nextSteps.get(i);
53  		}
54  	    }
55  	    return null;
56  	}
57  
58  	public boolean isLastStep() {
59  	    return this.lastStep;
60  	}
61  
62  	public boolean hasMoreSteps() {
63  	    return this.nextSteps.size() > 1;
64  	}
65      }
66  
67      private static Status root;
68  
69      static {
70  	root = new Status(Status.ROOT);
71  	Status ifNode = new Status(NodeType.IF_EXPR);
72  	Status ifSt = new Status(NodeType.IF_LAST_STATEMENT);
73  	Status ifStWithoutElse = new Status(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, true);
74  	Status elseSt = new Status(NodeType.ELSE_LAST_STATEMENT, true);
75  	Status whileNode = new Status(NodeType.WHILE_EXPR);
76  	Status whileSt = new Status(NodeType.WHILE_LAST_STATEMENT, true);
77  	Status switchNode = new Status(NodeType.SWITCH_START);
78  	Status caseSt = new Status(NodeType.CASE_LAST_STATEMENT);
79  	Status switchDefault = new Status(NodeType.SWITCH_LAST_DEFAULT_STATEMENT);
80  	Status switchEnd = new Status(NodeType.SWITCH_END, true);
81  
82  	Status forInit = new Status(NodeType.FOR_INIT);
83  	Status forExpr = new Status(NodeType.FOR_EXPR);
84  	Status forUpdate = new Status(NodeType.FOR_UPDATE);
85  	Status forSt = new Status(NodeType.FOR_BEFORE_FIRST_STATEMENT);
86  	Status forEnd = new Status(NodeType.FOR_END, true);
87  
88  	Status doSt = new Status(NodeType.DO_BEFORE_FIRST_STATEMENT);
89  	Status doExpr = new Status(NodeType.DO_EXPR, true);
90  
91  	Status labelNode = new Status(NodeType.LABEL_STATEMENT);
92  	Status labelEnd = new Status(NodeType.LABEL_LAST_STATEMENT, true);
93  
94  	root.addStep(ifNode);
95  	root.addStep(whileNode);
96  	root.addStep(switchNode);
97  	root.addStep(forInit);
98  	root.addStep(forExpr);
99  	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 }