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
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
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;
22 public class ForStatement extends Statement {
24 public Statement[] initializations;
25 public Expression condition;
26 public Statement[] increments;
27 public Statement action;
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;
34 private Label breakLabel, continueLabel;
36 // for local variables table attributes
37 int preCondInitStateIndex = -1;
38 int condIfTrueInitStateIndex = -1;
39 int mergedInitStateIndex = -1;
42 Statement[] initializations,
44 Statement[] increments,
52 this.initializations = initializations;
53 this.condition = condition;
54 this.increments = increments;
56 this.neededScope = neededScope;
59 public FlowInfo analyseCode(
60 BlockScope currentScope,
61 FlowContext flowContext,
64 breakLabel = new Label();
65 continueLabel = new Label();
67 // process the initializations
68 if (initializations != null) {
69 int count = initializations.length, i = 0;
71 flowInfo = initializations[i++].analyseCode(scope, flowContext, flowInfo);
74 preCondInitStateIndex =
75 currentScope.methodScope().recordInitializationStates(flowInfo);
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);
82 // process the condition
83 LoopingFlowContext condLoopContext = null;
84 if (condition != null) {
85 if (!conditionIsInlinedToTrue) {
87 condition.analyseCode(
90 new LoopingFlowContext(flowContext, this, null, null, scope)),
96 LoopingFlowContext loopingContext;
98 if ((action == null) || action.isEmptyBlock()) {
99 if (condLoopContext != null)
100 condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo);
101 if (conditionIsInlinedToTrue) {
102 return FlowInfo.DeadEnd;
104 if (conditionIsInlinedToFalse){
105 continueLabel = null; // for(;false;p());
107 actionInfo = flowInfo.initsWhenTrue().copy();
109 new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope);
113 new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope);
114 FlowInfo initsWhenTrue = flowInfo.initsWhenTrue();
115 condIfTrueInitStateIndex =
116 currentScope.methodScope().recordInitializationStates(initsWhenTrue);
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);
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;
131 if (condLoopContext != null)
132 condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo);
133 loopingContext.complainOnFinalAssignmentsInLoop(scope, actionInfo);
135 actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits());
139 if ((continueLabel != null) && (increments != null)) {
140 LoopingFlowContext loopContext =
141 new LoopingFlowContext(flowContext, this, null, null, scope);
142 int i = 0, count = increments.length;
144 actionInfo = increments[i++].analyseCode(scope, loopContext, actionInfo);
145 loopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo);
150 if (conditionIsInlinedToTrue) {
151 mergedInitStateIndex =
152 currentScope.methodScope().recordInitializationStates(
153 mergedInfo = loopingContext.initsOnBreak);
157 //end of loop: either condition false or break
159 flowInfo.initsWhenFalse().unconditionalInits().mergedWith(
160 loopingContext.initsOnBreak.unconditionalInits());
161 mergedInitStateIndex =
162 currentScope.methodScope().recordInitializationStates(mergedInfo);
167 * For statement code generation
169 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
170 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
172 public void generateCode(BlockScope currentScope, CodeStream codeStream) {
174 if ((bits & IsReachableMASK) == 0) {
177 int pc = codeStream.position;
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);
187 Label actionLabel = new Label(codeStream);
188 Label conditionLabel = new Label(codeStream);
189 breakLabel.codeStream = codeStream;
190 if (continueLabel != null) {
191 continueLabel.codeStream = codeStream;
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);
201 // generate the loop action
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(
209 condIfTrueInitStateIndex);
211 action.generateCode(scope, codeStream);
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);
224 // May loose some local variable initializations : affecting the local variable attributes
225 if (preCondInitStateIndex != -1) {
226 codeStream.removeNotDefinitelyAssignedVariables(
228 preCondInitStateIndex);
231 // generate the condition
232 conditionLabel.place();
233 if ((condition != null) && (condition.constant == NotAConstant)) {
234 condition.generateOptimizedBoolean(scope, codeStream, actionLabel, null, true);
236 if (continueLabel != null) {
237 codeStream.goto_(actionLabel);
242 // May loose some local variable initializations : affecting the local variable attributes
244 codeStream.exitUserScope(scope);
246 if (mergedInitStateIndex != -1) {
247 codeStream.removeNotDefinitelyAssignedVariables(
249 mergedInitStateIndex);
251 codeStream.recordPositionsFrom(pc, this.sourceStart);
254 public void resetStateForCodeGeneration() {
256 this.breakLabel.resetStateForCodeGeneration();
257 this.continueLabel.resetStateForCodeGeneration();
260 public void resolve(BlockScope upperScope) {
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);
271 if (increments != null)
272 for (int i = 0, length = increments.length; i < length; i++)
273 increments[i].resolve(scope);
275 action.resolve(scope);
278 public String toString(int tab) {
280 String s = tabString(tab) + "for ("; //$NON-NLS-1$
282 s = s + " //--NO upperscope scope needed\n" + tabString(tab) + " "; //$NON-NLS-2$ //$NON-NLS-1$
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$
292 s = s + "; "; //$NON-NLS-1$
294 if (condition != null)
295 s = s + condition.toStringExpression();
296 s = s + "; "; //$NON-NLS-1$
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$
306 s = s + ") "; //$NON-NLS-1$
309 s = s + "{}"; //$NON-NLS-1$
311 s = s + "\n" + action.toString(tab + 1); //$NON-NLS-1$
315 public void traverse(
316 IAbstractSyntaxTreeVisitor visitor,
317 BlockScope blockScope) {
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);
326 if (condition != null)
327 condition.traverse(visitor, scope);
329 if (increments != null) {
330 int incrementsLength = increments.length;
331 for (int i = 0; i < incrementsLength; i++)
332 increments[i].traverse(visitor, scope);
336 action.traverse(visitor, scope);
338 visitor.endVisit(this, blockScope);