Fix bug #672
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / WhileStatement.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
14 import net.sourceforge.phpdt.internal.compiler.codegen.Label;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.flow.LoopingFlowContext;
18 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
21
22 public class WhileStatement extends Statement {
23
24         public Expression condition;
25
26         public Statement action;
27
28         private Label breakLabel, continueLabel;
29
30         int preCondInitStateIndex = -1;
31
32         int condIfTrueInitStateIndex = -1;
33
34         int mergedInitStateIndex = -1;
35
36         public WhileStatement(Expression condition, Statement action, int s, int e) {
37
38                 this.condition = condition;
39                 this.action = action;
40                 sourceStart = s;
41                 sourceEnd = e;
42         }
43
44         public FlowInfo analyseCode(BlockScope currentScope,
45                         FlowContext flowContext, FlowInfo flowInfo) {
46
47                 breakLabel = new Label();
48                 continueLabel = new Label();
49
50                 Constant cst = this.condition.constant;
51                 boolean isConditionTrue = cst != NotAConstant
52                                 && cst.booleanValue() == true;
53                 boolean isConditionFalse = cst != NotAConstant
54                                 && cst.booleanValue() == false;
55
56                 cst = this.condition.optimizedBooleanConstant();
57                 boolean isConditionOptimizedTrue = cst != NotAConstant
58                                 && cst.booleanValue() == true;
59                 boolean isConditionOptimizedFalse = cst != NotAConstant
60                                 && cst.booleanValue() == false;
61
62                 preCondInitStateIndex = currentScope.methodScope()
63                                 .recordInitializationStates(flowInfo);
64                 LoopingFlowContext condLoopContext;
65                 FlowInfo postCondInfo = this.condition.analyseCode(currentScope,
66                                 (condLoopContext = new LoopingFlowContext(flowContext, this,
67                                                 null, null, currentScope)), flowInfo);
68
69                 LoopingFlowContext loopingContext;
70                 FlowInfo actionInfo;
71                 // if (action == null
72                 // || (action.isEmptyBlock() &&
73                 // currentScope.environment().options.complianceLevel <=
74                 // CompilerOptions.JDK1_3)) {
75                 // condLoopContext.complainOnFinalAssignmentsInLoop(currentScope,
76                 // postCondInfo);
77                 // if (isConditionTrue) {
78                 // return FlowInfo.DEAD_END;
79                 // } else {
80                 // FlowInfo mergedInfo =
81                 // postCondInfo.initsWhenFalse().unconditionalInits();
82                 // if (isConditionOptimizedTrue){
83                 // mergedInfo.setReachMode(FlowInfo.UNREACHABLE);
84                 // }
85                 // mergedInitStateIndex =
86                 // currentScope.methodScope().recordInitializationStates(mergedInfo);
87                 // return mergedInfo;
88                 // }
89                 // } else {
90                 // in case the condition was inlined to false, record the fact that
91                 // there is no way to reach any
92                 // statement inside the looping action
93                 loopingContext = new LoopingFlowContext(flowContext, this, breakLabel,
94                                 continueLabel, currentScope);
95                 if (isConditionFalse) {
96                         actionInfo = FlowInfo.DEAD_END;
97                 } else {
98                         actionInfo = postCondInfo.initsWhenTrue().copy();
99                         if (isConditionOptimizedFalse) {
100                                 actionInfo.setReachMode(FlowInfo.UNREACHABLE);
101                         }
102                 }
103
104                 // for computing local var attributes
105                 condIfTrueInitStateIndex = currentScope.methodScope()
106                                 .recordInitializationStates(postCondInfo.initsWhenTrue());
107
108                 if (!actionInfo.complainIfUnreachable(action, currentScope, false)) {
109                         actionInfo = action.analyseCode(currentScope, loopingContext,
110                                         actionInfo);
111                 }
112
113                 // code generation can be optimized when no need to continue in the loop
114                 if (!actionInfo.isReachable()
115                                 && !loopingContext.initsOnContinue.isReachable()) {
116                         continueLabel = null;
117                 } else {
118                         // TODO: (philippe) should simplify in one Loop context
119                         condLoopContext.complainOnFinalAssignmentsInLoop(currentScope,
120                                         postCondInfo);
121                         loopingContext.complainOnFinalAssignmentsInLoop(currentScope,
122                                         actionInfo);
123                 }
124                 // }
125
126                 // infinite loop
127                 FlowInfo mergedInfo;
128                 if (isConditionOptimizedTrue) {
129                         mergedInitStateIndex = currentScope.methodScope()
130                                         .recordInitializationStates(
131                                                         mergedInfo = loopingContext.initsOnBreak);
132                         return mergedInfo;
133                 }
134
135                 // end of loop: either condition false or break
136                 mergedInfo = postCondInfo.initsWhenFalse().unconditionalInits()
137                                 .mergedWith(loopingContext.initsOnBreak);
138                 if (isConditionOptimizedTrue && continueLabel == null) {
139                         mergedInfo.setReachMode(FlowInfo.UNREACHABLE);
140                 }
141                 mergedInitStateIndex = currentScope.methodScope()
142                                 .recordInitializationStates(mergedInfo);
143                 return mergedInfo;
144         }
145
146         /**
147          * While code generation
148          * 
149          * @param currentScope
150          *            net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
151          * @param codeStream
152          *            net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
153          */
154         // public void generateCode(BlockScope currentScope, CodeStream codeStream)
155         // {
156         //
157         // if ((bits & IsReachableMASK) == 0) {
158         // return;
159         // }
160         // int pc = codeStream.position;
161         // breakLabel.codeStream = codeStream;
162         //
163         // // generate condition
164         // if (continueLabel == null) {
165         // // no need to reverse condition
166         // if (condition.constant == NotAConstant) {
167         // condition.generateOptimizedBoolean(
168         // currentScope,
169         // codeStream,
170         // null,
171         // breakLabel,
172         // true);
173         // }
174         // } else {
175         // continueLabel.codeStream = codeStream;
176         // if (!(((condition.constant != NotAConstant)
177         // && (condition.constant.booleanValue() == true))
178         // || (action == null)
179         // || action.isEmptyBlock())) {
180         // int jumpPC = codeStream.position;
181         // codeStream.goto_(continueLabel);
182         // codeStream.recordPositionsFrom(jumpPC, condition.sourceStart);
183         // }
184         // }
185         // // generate the action
186         // Label actionLabel;
187         // (actionLabel = new Label(codeStream)).place();
188         // if (action != null) {
189         // // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for
190         // method appears incorrect
191         // if (condIfTrueInitStateIndex != -1) {
192         // // insert all locals initialized inside the condition into the action
193         // generated prior to the condition
194         // codeStream.addDefinitelyAssignedVariables(
195         // currentScope,
196         // condIfTrueInitStateIndex);
197         // }
198         // action.generateCode(currentScope, codeStream);
199         // // May loose some local variable initializations : affecting the local
200         // variable attributes
201         // if (preCondInitStateIndex != -1) {
202         // codeStream.removeNotDefinitelyAssignedVariables(
203         // currentScope,
204         // preCondInitStateIndex);
205         // }
206         //
207         // }
208         // // output condition and branch back to the beginning of the repeated
209         // action
210         // if (continueLabel != null) {
211         // continueLabel.place();
212         // condition.generateOptimizedBoolean(
213         // currentScope,
214         // codeStream,
215         // actionLabel,
216         // null,
217         // true);
218         // }
219         // breakLabel.place();
220         //
221         // // May loose some local variable initializations : affecting the local
222         // variable attributes
223         // if (mergedInitStateIndex != -1) {
224         // codeStream.removeNotDefinitelyAssignedVariables(
225         // currentScope,
226         // mergedInitStateIndex);
227         // }
228         // codeStream.recordPositionsFrom(pc, this.sourceStart);
229         // }
230         public void resetStateForCodeGeneration() {
231                 if (this.breakLabel != null) {
232                         this.breakLabel.resetStateForCodeGeneration();
233                 }
234                 if (this.continueLabel != null) {
235                         this.continueLabel.resetStateForCodeGeneration();
236                 }
237         }
238
239         public StringBuffer printStatement(int tab, StringBuffer output) {
240
241                 printIndent(tab, output).append("while ("); //$NON-NLS-1$
242                 condition.printExpression(0, output).append(')');
243                 if (action == null)
244                         output.append(';');
245                 else
246                         action.printStatement(tab + 1, output);
247                 return output;
248         }
249
250         public void resolve(BlockScope scope) {
251
252                 TypeBinding type = condition
253                                 .resolveTypeExpecting(scope, BooleanBinding);
254                 condition.implicitWidening(type, type);
255                 if (action != null)
256                         action.resolve(scope);
257         }
258
259         public String toString(int tab) {
260
261                 String s = tabString(tab);
262                 s = s + "while (" + condition.toStringExpression() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
263                 if (action == null)
264                         s = s + " {} ;"; //$NON-NLS-1$ 
265                 else if (action instanceof Block)
266                         s = s + "\n" + action.toString(tab + 1); //$NON-NLS-1$
267                 else
268                         s = s + " {\n" + action.toString(tab + 1) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
269                 return s;
270         }
271
272         public void traverse(ASTVisitor visitor, BlockScope blockScope) {
273
274                 if (visitor.visit(this, blockScope)) {
275                         condition.traverse(visitor, blockScope);
276                         if (action != null)
277                                 action.traverse(visitor, blockScope);
278                 }
279                 visitor.endVisit(this, blockScope);
280         }
281 }