001: /*
002: $Id: LabelVerifier.java 3419 2006-01-19 00:07:02Z blackdrag $
003:
004: Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005:
006: Redistribution and use of this software and associated documentation
007: ("Software"), with or without modification, are permitted provided
008: that the following conditions are met:
009:
010: 1. Redistributions of source code must retain copyright
011: statements and notices. Redistributions must also contain a
012: copy of this document.
013:
014: 2. Redistributions in binary form must reproduce the
015: above copyright notice, this list of conditions and the
016: following disclaimer in the documentation and/or other
017: materials provided with the distribution.
018:
019: 3. The name "groovy" must not be used to endorse or promote
020: products derived from this Software without prior written
021: permission of The Codehaus. For written permission,
022: please contact info@codehaus.org.
023:
024: 4. Products derived from this Software may not be called "groovy"
025: nor may "groovy" appear in their names without prior written
026: permission of The Codehaus. "groovy" is a registered
027: trademark of The Codehaus.
028:
029: 5. Due credit should be given to The Codehaus -
030: http://groovy.codehaus.org/
031:
032: THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033: ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034: NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
036: THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043: OF THE POSSIBILITY OF SUCH DAMAGE.
044:
045: */
046: package org.codehaus.groovy.control;
047:
048: import java.util.Iterator;
049: import java.util.LinkedList;
050:
051: import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
052: import org.codehaus.groovy.ast.stmt.BreakStatement;
053: import org.codehaus.groovy.ast.stmt.ContinueStatement;
054: import org.codehaus.groovy.ast.stmt.DoWhileStatement;
055: import org.codehaus.groovy.ast.stmt.ForStatement;
056: import org.codehaus.groovy.ast.stmt.Statement;
057: import org.codehaus.groovy.ast.stmt.SwitchStatement;
058: import org.codehaus.groovy.ast.stmt.WhileStatement;
059:
060: /**
061: * This class checks the handling of labels in the AST
062: *
063: * @author Jochen Theodorou
064: */
065: public class LabelVerifier extends ClassCodeVisitorSupport {
066:
067: private SourceUnit source;
068: private LinkedList visitedLabels;
069: private LinkedList continueLabels;
070: private LinkedList breakLabels;
071: boolean inLoop = false;
072: boolean inSwitch = false;
073:
074: public LabelVerifier(SourceUnit src) {
075: source = src;
076: }
077:
078: protected SourceUnit getSourceUnit() {
079: return source;
080: }
081:
082: private void init() {
083: visitedLabels = new LinkedList();
084: continueLabels = new LinkedList();
085: breakLabels = new LinkedList();
086: inLoop = false;
087: inSwitch = false;
088: }
089:
090: protected void visitClassCodeContainer(Statement code) {
091: init();
092: super .visitClassCodeContainer(code);
093: assertNoLabelsMissed();
094: }
095:
096: public void visitStatement(Statement statement) {
097: String label = statement.getStatementLabel();
098:
099: if (label != null) {
100: for (Iterator iter = breakLabels.iterator(); iter.hasNext();) {
101: BreakStatement element = (BreakStatement) iter.next();
102: if (element.getLabel().equals(label))
103: iter.remove();
104: }
105:
106: for (Iterator iter = continueLabels.iterator(); iter
107: .hasNext();) {
108: ContinueStatement element = (ContinueStatement) iter
109: .next();
110: if (element.getLabel().equals(label))
111: iter.remove();
112: }
113:
114: visitedLabels.add(label);
115: }
116:
117: super .visitStatement(statement);
118: }
119:
120: public void visitForLoop(ForStatement forLoop) {
121: boolean oldInLoop = inLoop;
122: inLoop = true;
123: super .visitForLoop(forLoop);
124: inLoop = oldInLoop;
125: }
126:
127: public void visitDoWhileLoop(DoWhileStatement loop) {
128: boolean oldInLoop = inLoop;
129: inLoop = true;
130: super .visitDoWhileLoop(loop);
131: inLoop = oldInLoop;
132: }
133:
134: public void visitWhileLoop(WhileStatement loop) {
135: boolean oldInLoop = inLoop;
136: inLoop = true;
137: super .visitWhileLoop(loop);
138: inLoop = oldInLoop;
139: }
140:
141: public void visitBreakStatement(BreakStatement statement) {
142: String label = statement.getLabel();
143: boolean hasNamedLabel = label != null;
144: if (!hasNamedLabel && !inLoop && !inSwitch) {
145: addError(
146: "the break statement is only allowed inside loops or switches",
147: statement);
148: } else if (hasNamedLabel && !inLoop) {
149: addError(
150: "the break statement with named label is only allowed inside loops",
151: statement);
152: }
153: if (label != null) {
154: boolean found = false;
155: for (Iterator iter = visitedLabels.iterator(); iter
156: .hasNext();) {
157: String element = (String) iter.next();
158: if (element.equals(label)) {
159: found = true;
160: break;
161: }
162: }
163: if (!found)
164: breakLabels.add(statement);
165: }
166:
167: super .visitBreakStatement(statement);
168: }
169:
170: public void visitContinueStatement(ContinueStatement statement) {
171: String label = statement.getLabel();
172: boolean hasNamedLabel = label != null;
173: if (!hasNamedLabel && !inLoop) {
174: addError(
175: "the continue statement is only allowed inside loops",
176: statement);
177: }
178: if (label != null) {
179: boolean found = false;
180: for (Iterator iter = visitedLabels.iterator(); iter
181: .hasNext();) {
182: String element = (String) iter.next();
183: if (element.equals(label)) {
184: found = true;
185: break;
186: }
187: }
188: if (!found)
189: continueLabels.add(statement);
190: }
191:
192: super .visitContinueStatement(statement);
193: }
194:
195: protected void assertNoLabelsMissed() {
196: //TODO: report multiple missing labels of the same name only once
197: for (Iterator iter = continueLabels.iterator(); iter.hasNext();) {
198: ContinueStatement element = (ContinueStatement) iter.next();
199: addError("continue to missing label", element);
200: }
201: for (Iterator iter = breakLabels.iterator(); iter.hasNext();) {
202: BreakStatement element = (BreakStatement) iter.next();
203: addError("break to missing label", element);
204: }
205: }
206:
207: public void visitSwitch(SwitchStatement statement) {
208: inSwitch = true;
209: super.visitSwitch(statement);
210: }
211:
212: }
|