Fixes for bug #1326088
[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
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                 Constant cst = this.condition.constant;
49                 boolean isConditionTrue = cst != NotAConstant && cst.booleanValue() == true;
50                 boolean isConditionFalse = cst != NotAConstant && cst.booleanValue() == false;
51
52                 cst = this.condition.optimizedBooleanConstant();
53                 boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true;
54                 boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false;
55                 
56                 preCondInitStateIndex =
57                         currentScope.methodScope().recordInitializationStates(flowInfo);
58                 LoopingFlowContext condLoopContext;
59                 FlowInfo postCondInfo =
60                         this.condition.analyseCode(
61                                 currentScope,
62                                 (condLoopContext =
63                                         new LoopingFlowContext(flowContext, this, null, null, currentScope)),
64                                 flowInfo);
65
66                 LoopingFlowContext loopingContext;
67                 FlowInfo actionInfo;
68 //              if (action == null 
69 //                      || (action.isEmptyBlock() && currentScope.environment().options.complianceLevel <= CompilerOptions.JDK1_3)) {
70 //                      condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo);
71 //                      if (isConditionTrue) {
72 //                              return FlowInfo.DEAD_END;
73 //                      } else {
74 //                              FlowInfo mergedInfo = postCondInfo.initsWhenFalse().unconditionalInits();
75 //                              if (isConditionOptimizedTrue){
76 //                                      mergedInfo.setReachMode(FlowInfo.UNREACHABLE);
77 //                              }
78 //                              mergedInitStateIndex =
79 //                                      currentScope.methodScope().recordInitializationStates(mergedInfo);
80 //                              return mergedInfo;
81 //                      }
82 //              } else {
83                         // in case the condition was inlined to false, record the fact that there is no way to reach any 
84                         // statement inside the looping action
85                         loopingContext =
86                                 new LoopingFlowContext(
87                                         flowContext,
88                                         this,
89                                         breakLabel,
90                                         continueLabel,
91                                         currentScope);
92                         if (isConditionFalse) {
93                                 actionInfo = FlowInfo.DEAD_END;
94                         } else {
95                                 actionInfo = postCondInfo.initsWhenTrue().copy();
96                                 if (isConditionOptimizedFalse){
97                                         actionInfo.setReachMode(FlowInfo.UNREACHABLE);
98                                 }
99                         }
100
101                         // for computing local var attributes
102                         condIfTrueInitStateIndex =
103                                 currentScope.methodScope().recordInitializationStates(
104                                         postCondInfo.initsWhenTrue());
105
106                         if (!actionInfo.complainIfUnreachable(action, currentScope, false)) {
107                                 actionInfo = action.analyseCode(currentScope, loopingContext, actionInfo);
108                         }
109
110                         // code generation can be optimized when no need to continue in the loop
111                         if (!actionInfo.isReachable() && !loopingContext.initsOnContinue.isReachable()) {
112                                 continueLabel = null;
113                         } else {
114                                 // TODO: (philippe) should simplify in one Loop context
115                                 condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo);
116                                 loopingContext.complainOnFinalAssignmentsInLoop(currentScope, actionInfo);
117                         }
118 //              }
119
120                 // infinite loop
121                 FlowInfo mergedInfo;
122                 if (isConditionOptimizedTrue) {
123                         mergedInitStateIndex =
124                                 currentScope.methodScope().recordInitializationStates(
125                                         mergedInfo = loopingContext.initsOnBreak);
126                         return mergedInfo;
127                 }
128
129                 // end of loop: either condition false or break
130                 mergedInfo =
131                         postCondInfo.initsWhenFalse().unconditionalInits().mergedWith(
132                                 loopingContext.initsOnBreak);
133                 if (isConditionOptimizedTrue && continueLabel == null){
134                         mergedInfo.setReachMode(FlowInfo.UNREACHABLE);
135                 }
136                 mergedInitStateIndex =
137                         currentScope.methodScope().recordInitializationStates(mergedInfo);
138                 return mergedInfo;
139         }
140
141         /**
142          * While code generation
143          *
144          * @param currentScope net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
145          * @param codeStream net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
146          */
147 //      public void generateCode(BlockScope currentScope, CodeStream codeStream) {
148 //
149 //              if ((bits & IsReachableMASK) == 0) {
150 //                      return;
151 //              }
152 //              int pc = codeStream.position;
153 //              breakLabel.codeStream = codeStream;
154 //
155 //              // generate condition
156 //              if (continueLabel == null) {
157 //                      // no need to reverse condition
158 //                      if (condition.constant == NotAConstant) {
159 //                              condition.generateOptimizedBoolean(
160 //                                      currentScope,
161 //                                      codeStream,
162 //                                      null,
163 //                                      breakLabel,
164 //                                      true);
165 //                      }
166 //              } else {
167 //                      continueLabel.codeStream = codeStream;
168 //                      if (!(((condition.constant != NotAConstant)
169 //                              && (condition.constant.booleanValue() == true))
170 //                              || (action == null)
171 //                              || action.isEmptyBlock())) {
172 //                              int jumpPC = codeStream.position;
173 //                              codeStream.goto_(continueLabel);
174 //                              codeStream.recordPositionsFrom(jumpPC, condition.sourceStart);
175 //                      }
176 //              }
177 //              // generate the action
178 //              Label actionLabel;
179 //              (actionLabel = new Label(codeStream)).place();
180 //              if (action != null) {
181 //                      // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
182 //                      if (condIfTrueInitStateIndex != -1) {
183 //                              // insert all locals initialized inside the condition into the action generated prior to the condition
184 //                              codeStream.addDefinitelyAssignedVariables(
185 //                                      currentScope,
186 //                                      condIfTrueInitStateIndex);
187 //                      }
188 //                      action.generateCode(currentScope, codeStream);
189 //                      // May loose some local variable initializations : affecting the local variable attributes
190 //                      if (preCondInitStateIndex != -1) {
191 //                              codeStream.removeNotDefinitelyAssignedVariables(
192 //                                      currentScope,
193 //                                      preCondInitStateIndex);
194 //                      }
195 //
196 //              }
197 //              // output condition and branch back to the beginning of the repeated action
198 //              if (continueLabel != null) {
199 //                      continueLabel.place();
200 //                      condition.generateOptimizedBoolean(
201 //                              currentScope,
202 //                              codeStream,
203 //                              actionLabel,
204 //                              null,
205 //                              true);
206 //              }
207 //              breakLabel.place();
208 //
209 //              // May loose some local variable initializations : affecting the local variable attributes
210 //              if (mergedInitStateIndex != -1) {
211 //                      codeStream.removeNotDefinitelyAssignedVariables(
212 //                              currentScope,
213 //                              mergedInitStateIndex);
214 //              }
215 //              codeStream.recordPositionsFrom(pc, this.sourceStart);
216 //      }
217
218         public void resetStateForCodeGeneration() {
219                 if (this.breakLabel != null) {
220                         this.breakLabel.resetStateForCodeGeneration();
221                 }
222                 if (this.continueLabel != null) {
223                         this.continueLabel.resetStateForCodeGeneration();
224                 }
225         }
226         public StringBuffer printStatement(int tab, StringBuffer output) {
227
228                 printIndent(tab, output).append("while ("); //$NON-NLS-1$
229                 condition.printExpression(0, output).append(')');
230                 if (action == null)
231                         output.append(';');
232                 else
233                         action.printStatement(tab + 1, output); 
234                 return output;
235         }
236         public void resolve(BlockScope scope) {
237
238                 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
239                 condition.implicitWidening(type, type);
240                 if (action != null)
241                         action.resolve(scope);
242         }
243
244         public String toString(int tab) {
245
246                 String s = tabString(tab);
247                 s = s + "while (" + condition.toStringExpression() + ")";       //$NON-NLS-1$ //$NON-NLS-2$
248                 if (action == null)
249                         s = s + " {} ;"; //$NON-NLS-1$ 
250                 else if (action instanceof Block)
251                         s = s + "\n" + action.toString(tab + 1); //$NON-NLS-1$
252                 else
253                         s = s + " {\n" + action.toString(tab + 1) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
254                 return s;
255         }
256
257         public void traverse(
258             ASTVisitor visitor,
259                 BlockScope blockScope) {
260
261                 if (visitor.visit(this, blockScope)) {
262                         condition.traverse(visitor, blockScope);
263                         if (action != null)
264                                 action.traverse(visitor, blockScope);
265                 }
266                 visitor.endVisit(this, blockScope);
267         }
268 }