f70514049b81f5e0ce2d2de4c52590c1c95d4513
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / ForStatement.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.lookup.BlockScope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
21
22 public class ForStatement extends Statement {
23         
24         public Statement[] initializations;
25         public Expression condition;
26         public Statement[] increments;
27         public Statement action;
28
29         //when there is no local declaration, there is no need of a new scope
30         //scope is positionned either to a new scope, or to the "upper"scope (see resolveType)
31         public boolean neededScope;
32         public BlockScope scope;
33
34         private Label breakLabel, continueLabel;
35
36         // for local variables table attributes
37         int preCondInitStateIndex = -1;
38         int condIfTrueInitStateIndex = -1;
39         int mergedInitStateIndex = -1;
40
41         public ForStatement(
42                 Statement[] initializations,
43                 Expression condition,
44                 Statement[] increments,
45                 Statement action,
46                 boolean neededScope,
47                 int s,
48                 int e) {
49
50                 this.sourceStart = s;
51                 this.sourceEnd = e;
52                 this.initializations = initializations;
53                 this.condition = condition;
54                 this.increments = increments;
55                 this.action = action;
56                 this.neededScope = neededScope;
57         }
58
59         public FlowInfo analyseCode(
60                 BlockScope currentScope,
61                 FlowContext flowContext,
62                 FlowInfo flowInfo) {
63                         
64                 breakLabel = new Label();
65                 continueLabel = new Label();
66
67                 // process the initializations
68                 if (initializations != null) {
69                         int count = initializations.length, i = 0;
70                         while (i < count) {
71                                 flowInfo = initializations[i++].analyseCode(scope, flowContext, flowInfo);
72                         }
73                 }
74                 preCondInitStateIndex =
75                         currentScope.methodScope().recordInitializationStates(flowInfo);
76
77                 boolean conditionIsInlinedToTrue = 
78                         condition == null || (condition.constant != NotAConstant && condition.constant.booleanValue() == true);
79                 boolean conditionIsInlinedToFalse = 
80                         ! conditionIsInlinedToTrue && (condition.constant != NotAConstant && condition.constant.booleanValue() == false);
81                 
82                 // process the condition
83                 LoopingFlowContext condLoopContext = null;
84                 if (condition != null) {
85                         if (!conditionIsInlinedToTrue) {
86                                 flowInfo =
87                                         condition.analyseCode(
88                                                 scope,
89                                                 (condLoopContext =
90                                                         new LoopingFlowContext(flowContext, this, null, null, scope)),
91                                                 flowInfo);
92                         }
93                 }
94
95                 // process the action
96                 LoopingFlowContext loopingContext;
97                 FlowInfo actionInfo;
98                 if ((action == null) || action.isEmptyBlock()) {
99                         if (condLoopContext != null)
100                                 condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo);
101                         if (conditionIsInlinedToTrue) {
102                                 return FlowInfo.DeadEnd;
103                         } else {
104                                 if (conditionIsInlinedToFalse){
105                                         continueLabel = null; // for(;false;p());
106                                 }
107                                 actionInfo = flowInfo.initsWhenTrue().copy();
108                                 loopingContext =
109                                         new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope);
110                         }
111                 } else {
112                         loopingContext =
113                                 new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope);
114                         FlowInfo initsWhenTrue = flowInfo.initsWhenTrue();
115                         condIfTrueInitStateIndex =
116                                 currentScope.methodScope().recordInitializationStates(initsWhenTrue);
117
118                                 actionInfo = conditionIsInlinedToFalse
119                                         ? FlowInfo.DeadEnd  // unreachable when condition inlined to false
120                                         : initsWhenTrue.copy();
121                         if (!actionInfo.complainIfUnreachable(action, scope)) {
122                                 actionInfo = action.analyseCode(scope, loopingContext, actionInfo);
123                         }
124
125                         // code generation can be optimized when no need to continue in the loop
126                         if (((actionInfo == FlowInfo.DeadEnd) || actionInfo.isFakeReachable())
127                                 && ((loopingContext.initsOnContinue == FlowInfo.DeadEnd)
128                                         || loopingContext.initsOnContinue.isFakeReachable())) {
129                                 continueLabel = null;
130                         } else {
131                                 if (condLoopContext != null)
132                                         condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo);
133                                 loopingContext.complainOnFinalAssignmentsInLoop(scope, actionInfo);
134                                 actionInfo =
135                                         actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits());
136                                 // for increments
137                         }
138                 }
139                 if ((continueLabel != null) && (increments != null)) {
140                         LoopingFlowContext loopContext =
141                                 new LoopingFlowContext(flowContext, this, null, null, scope);
142                         int i = 0, count = increments.length;
143                         while (i < count)
144                                 actionInfo = increments[i++].analyseCode(scope, loopContext, actionInfo);
145                         loopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo);
146                 }
147
148                 // infinite loop
149                 FlowInfo mergedInfo;
150                 if (conditionIsInlinedToTrue) {
151                         mergedInitStateIndex =
152                                 currentScope.methodScope().recordInitializationStates(
153                                         mergedInfo = loopingContext.initsOnBreak);
154                         return mergedInfo;
155                 }
156
157                 //end of loop: either condition false or break
158                 mergedInfo =
159                         flowInfo.initsWhenFalse().unconditionalInits().mergedWith(
160                                 loopingContext.initsOnBreak.unconditionalInits());
161                 mergedInitStateIndex =
162                         currentScope.methodScope().recordInitializationStates(mergedInfo);
163                 return mergedInfo;
164         }
165
166         /**
167          * For statement code generation
168          *
169          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
170          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
171          */
172         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
173
174                 if ((bits & IsReachableMASK) == 0) {
175                         return;
176                 }
177                 int pc = codeStream.position;
178
179                 // generate the initializations
180                 if (initializations != null) {
181                         for (int i = 0, max = initializations.length; i < max; i++) {
182                                 initializations[i].generateCode(scope, codeStream);
183                         }
184                 }
185
186                 // label management
187                 Label actionLabel = new Label(codeStream);
188                 Label conditionLabel = new Label(codeStream);
189                 breakLabel.codeStream = codeStream;
190                 if (continueLabel != null) {
191                         continueLabel.codeStream = codeStream;
192                 }
193                 // jump over the actionBlock
194                 if ((condition != null)
195                         && (condition.constant == NotAConstant)
196                         && !((action == null || action.isEmptyBlock()) && (increments == null))) {
197                         int jumpPC = codeStream.position;
198                         codeStream.goto_(conditionLabel);
199                         codeStream.recordPositionsFrom(jumpPC, condition.sourceStart);
200                 }
201                 // generate the loop action
202                 actionLabel.place();
203                 if (action != null) {
204                         // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
205                         if (condIfTrueInitStateIndex != -1) {
206                                 // insert all locals initialized inside the condition into the action generated prior to the condition
207                                 codeStream.addDefinitelyAssignedVariables(
208                                         currentScope,
209                                         condIfTrueInitStateIndex);
210                         }
211                         action.generateCode(scope, codeStream);
212                 }
213                 // continuation point
214                 if (continueLabel != null) {
215                         continueLabel.place();
216                         // generate the increments for next iteration
217                         if (increments != null) {
218                                 for (int i = 0, max = increments.length; i < max; i++) {
219                                         increments[i].generateCode(scope, codeStream);
220                                 }
221                         }
222                 }
223
224                 // May loose some local variable initializations : affecting the local variable attributes
225                 if (preCondInitStateIndex != -1) {
226                         codeStream.removeNotDefinitelyAssignedVariables(
227                                 currentScope,
228                                 preCondInitStateIndex);
229                 }
230
231                 // generate the condition
232                 conditionLabel.place();
233                 if ((condition != null) && (condition.constant == NotAConstant)) {
234                         condition.generateOptimizedBoolean(scope, codeStream, actionLabel, null, true);
235                 } else {
236                         if (continueLabel != null) {
237                                 codeStream.goto_(actionLabel);
238                         }
239                 }
240                 breakLabel.place();
241
242                 // May loose some local variable initializations : affecting the local variable attributes
243                 if (neededScope) {
244                         codeStream.exitUserScope(scope);
245                 }
246                 if (mergedInitStateIndex != -1) {
247                         codeStream.removeNotDefinitelyAssignedVariables(
248                                 currentScope,
249                                 mergedInitStateIndex);
250                 }
251                 codeStream.recordPositionsFrom(pc, this.sourceStart);
252         }
253
254         public void resetStateForCodeGeneration() {
255
256                 this.breakLabel.resetStateForCodeGeneration();
257                 this.continueLabel.resetStateForCodeGeneration();
258         }
259
260         public void resolve(BlockScope upperScope) {
261
262                 // use the scope that will hold the init declarations
263                 scope = neededScope ? new BlockScope(upperScope) : upperScope;
264                 if (initializations != null)
265                         for (int i = 0, length = initializations.length; i < length; i++)
266                                 initializations[i].resolve(scope);
267                 if (condition != null) {
268                         TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
269                         condition.implicitWidening(type, type);
270                 }
271                 if (increments != null)
272                         for (int i = 0, length = increments.length; i < length; i++)
273                                 increments[i].resolve(scope);
274                 if (action != null)
275                         action.resolve(scope);
276         }
277
278         public String toString(int tab) {
279
280                 String s = tabString(tab) + "for ("; //$NON-NLS-1$
281                 if (!neededScope)
282                         s = s + " //--NO upperscope scope needed\n" + tabString(tab) + "     "; //$NON-NLS-2$ //$NON-NLS-1$
283                 //inits
284                 if (initializations != null) {
285                         for (int i = 0; i < initializations.length; i++) {
286                                 //nice only with expressions
287                                 s = s + initializations[i].toString(0);
288                                 if (i != (initializations.length - 1))
289                                         s = s + " , "; //$NON-NLS-1$
290                         }
291                 }; 
292                 s = s + "; "; //$NON-NLS-1$
293                 //cond
294                 if (condition != null)
295                         s = s + condition.toStringExpression();
296                 s = s + "; "; //$NON-NLS-1$
297                 //updates
298                 if (increments != null) {
299                         for (int i = 0; i < increments.length; i++) {
300                                 //nice only with expressions
301                                 s = s + increments[i].toString(0);
302                                 if (i != (increments.length - 1))
303                                         s = s + " , "; //$NON-NLS-1$
304                         }
305                 }; 
306                 s = s + ") "; //$NON-NLS-1$
307                 //block
308                 if (action == null)
309                         s = s + "{}"; //$NON-NLS-1$
310                 else
311                         s = s + "\n" + action.toString(tab + 1); //$NON-NLS-1$
312                 return s;
313         }
314         
315         public void traverse(
316                 IAbstractSyntaxTreeVisitor visitor,
317                 BlockScope blockScope) {
318
319                 if (visitor.visit(this, blockScope)) {
320                         if (initializations != null) {
321                                 int initializationsLength = initializations.length;
322                                 for (int i = 0; i < initializationsLength; i++)
323                                         initializations[i].traverse(visitor, scope);
324                         }
325
326                         if (condition != null)
327                                 condition.traverse(visitor, scope);
328
329                         if (increments != null) {
330                                 int incrementsLength = increments.length;
331                                 for (int i = 0; i < incrementsLength; i++)
332                                         increments[i].traverse(visitor, scope);
333                         }
334
335                         if (action != null)
336                                 action.traverse(visitor, scope);
337                 }
338                 visitor.endVisit(this, blockScope);
339         }
340 }