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