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