1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.codehaus.groovy.control;
47
48 import java.util.Iterator;
49 import java.util.LinkedList;
50
51 import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
52 import org.codehaus.groovy.ast.stmt.BreakStatement;
53 import org.codehaus.groovy.ast.stmt.ContinueStatement;
54 import org.codehaus.groovy.ast.stmt.DoWhileStatement;
55 import org.codehaus.groovy.ast.stmt.ForStatement;
56 import org.codehaus.groovy.ast.stmt.Statement;
57 import org.codehaus.groovy.ast.stmt.SwitchStatement;
58 import org.codehaus.groovy.ast.stmt.WhileStatement;
59
60 /***
61 * This class checks the handling of labels in the AST
62 *
63 * @author Jochen Theodorou
64 */
65 public class LabelVerifier extends ClassCodeVisitorSupport {
66
67 private SourceUnit source;
68 private LinkedList visitedLabels;
69 private LinkedList continueLabels;
70 private LinkedList breakLabels;
71 boolean inLoop=false;
72 boolean inSwitch=false;
73
74 public LabelVerifier(SourceUnit src) {
75 source = src;
76 }
77
78 protected SourceUnit getSourceUnit() {
79 return source;
80 }
81
82 private void init(){
83 visitedLabels = new LinkedList();
84 continueLabels = new LinkedList();
85 breakLabels = new LinkedList();
86 inLoop=false;
87 inSwitch=false;
88 }
89
90 protected void visitClassCodeContainer(Statement code) {
91 init();
92 super.visitClassCodeContainer(code);
93 assertNoLabelsMissed();
94 }
95
96 public void visitStatement(Statement statement) {
97 String label = statement.getStatementLabel();
98
99 if (label!=null) {
100 for (Iterator iter = breakLabels.iterator(); iter.hasNext();) {
101 BreakStatement element = (BreakStatement) iter.next();
102 if (element.getLabel().equals(label)) iter.remove();
103 }
104
105 for (Iterator iter = continueLabels.iterator(); iter.hasNext();) {
106 ContinueStatement element = (ContinueStatement) iter.next();
107 if (element.getLabel().equals(label)) iter.remove();
108 }
109
110 visitedLabels.add(label);
111 }
112
113 super.visitStatement(statement);
114 }
115
116 public void visitForLoop(ForStatement forLoop) {
117 boolean oldInLoop = inLoop;
118 inLoop = true;
119 super.visitForLoop(forLoop);
120 inLoop = oldInLoop;
121 }
122
123 public void visitDoWhileLoop(DoWhileStatement loop) {
124 boolean oldInLoop = inLoop;
125 inLoop = true;
126 super.visitDoWhileLoop(loop);
127 inLoop = oldInLoop;
128 }
129
130 public void visitWhileLoop(WhileStatement loop) {
131 boolean oldInLoop = inLoop;
132 inLoop = true;
133 super.visitWhileLoop(loop);
134 inLoop = oldInLoop;
135 }
136
137 public void visitBreakStatement(BreakStatement statement) {
138 String label = statement.getLabel();
139 boolean hasNamedLabel = label!=null;
140 if (!hasNamedLabel && !inLoop && !inSwitch) {
141 addError("the break statement is only allowed inside loops or switches",statement);
142 } else if (hasNamedLabel && !inLoop) {
143 addError("the break statement with named label is only allowed inside loops",statement);
144 }
145 if (label!=null) {
146 boolean found=false;
147 for (Iterator iter = visitedLabels.iterator(); iter.hasNext();) {
148 String element = (String) iter.next();
149 if (element.equals(label)) {
150 found = true;
151 break;
152 }
153 }
154 if (!found) breakLabels.add(statement);
155 }
156
157 super.visitBreakStatement(statement);
158 }
159
160 public void visitContinueStatement(ContinueStatement statement) {
161 String label = statement.getLabel();
162 boolean hasNamedLabel = label!=null;
163 if (!hasNamedLabel && !inLoop) {
164 addError("the continue statement is only allowed inside loops",statement);
165 }
166 if (label!=null) {
167 boolean found=false;
168 for (Iterator iter = visitedLabels.iterator(); iter.hasNext();) {
169 String element = (String) iter.next();
170 if (element.equals(label)) {
171 found = true;
172 break;
173 }
174 }
175 if (!found) continueLabels.add(statement);
176 }
177
178 super.visitContinueStatement(statement);
179 }
180
181 protected void assertNoLabelsMissed() {
182
183 for (Iterator iter = continueLabels.iterator(); iter.hasNext();) {
184 ContinueStatement element = (ContinueStatement) iter.next();
185 addError("continue to missing label",element);
186 }
187 for (Iterator iter = breakLabels.iterator(); iter.hasNext();) {
188 BreakStatement element = (BreakStatement) iter.next();
189 addError("break to missing label",element);
190 }
191 }
192
193 public void visitSwitch(SwitchStatement statement) {
194 inSwitch=true;
195 super.visitSwitch(statement);
196 }
197
198 }