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.*;
15 import net.sourceforge.phpdt.internal.compiler.flow.*;
16 import net.sourceforge.phpdt.internal.compiler.lookup.*;
18 public class ForStatement extends Statement {
20 public Statement[] initializations;
21 public Expression condition;
22 public Statement[] increments;
23 public Statement action;
25 //when there is no local declaration, there is no need of a new scope
26 //scope is positionned either to a new scope, or to the "upper"scope (see resolveType)
27 public boolean neededScope;
28 public BlockScope scope;
30 private Label breakLabel, continueLabel;
32 // for local variables table attributes
33 int preCondInitStateIndex = -1;
34 int condIfTrueInitStateIndex = -1;
35 int mergedInitStateIndex = -1;
38 Statement[] initializations,
40 Statement[] increments,
48 this.initializations = initializations;
49 this.condition = condition;
50 this.increments = increments;
52 this.neededScope = neededScope;
55 public FlowInfo analyseCode(
56 BlockScope currentScope,
57 FlowContext flowContext,
60 breakLabel = new Label();
61 continueLabel = new Label();
63 // process the initializations
64 if (initializations != null) {
65 int count = initializations.length, i = 0;
67 flowInfo = initializations[i++].analyseCode(scope, flowContext, flowInfo);
70 preCondInitStateIndex =
71 currentScope.methodScope().recordInitializationStates(flowInfo);
73 boolean conditionIsInlinedToTrue =
74 condition == null || (condition.constant != NotAConstant && condition.constant.booleanValue() == true);
75 boolean conditionIsInlinedToFalse =
76 ! conditionIsInlinedToTrue && (condition.constant != NotAConstant && condition.constant.booleanValue() == false);
78 // process the condition
79 LoopingFlowContext condLoopContext = null;
80 if (condition != null) {
81 if (!conditionIsInlinedToTrue) {
83 condition.analyseCode(
86 new LoopingFlowContext(flowContext, this, null, null, scope)),
92 LoopingFlowContext loopingContext;
94 if ((action == null) || action.isEmptyBlock()) {
95 if (condLoopContext != null)
96 condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo);
97 if (conditionIsInlinedToTrue) {
98 return FlowInfo.DeadEnd;
100 if (conditionIsInlinedToFalse){
101 continueLabel = null; // for(;false;p());
103 actionInfo = flowInfo.initsWhenTrue().copy();
105 new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope);
109 new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope);
110 FlowInfo initsWhenTrue = flowInfo.initsWhenTrue();
111 condIfTrueInitStateIndex =
112 currentScope.methodScope().recordInitializationStates(initsWhenTrue);
114 actionInfo = conditionIsInlinedToFalse
115 ? FlowInfo.DeadEnd // unreachable when condition inlined to false
116 : initsWhenTrue.copy();
117 if (!actionInfo.complainIfUnreachable(action, scope)) {
118 actionInfo = action.analyseCode(scope, loopingContext, actionInfo);
121 // code generation can be optimized when no need to continue in the loop
122 if (((actionInfo == FlowInfo.DeadEnd) || actionInfo.isFakeReachable())
123 && ((loopingContext.initsOnContinue == FlowInfo.DeadEnd)
124 || loopingContext.initsOnContinue.isFakeReachable())) {
125 continueLabel = null;
127 if (condLoopContext != null)
128 condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo);
129 loopingContext.complainOnFinalAssignmentsInLoop(scope, actionInfo);
131 actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits());
135 if ((continueLabel != null) && (increments != null)) {
136 LoopingFlowContext loopContext =
137 new LoopingFlowContext(flowContext, this, null, null, scope);
138 int i = 0, count = increments.length;
140 actionInfo = increments[i++].analyseCode(scope, loopContext, actionInfo);
141 loopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo);
146 if (conditionIsInlinedToTrue) {
147 mergedInitStateIndex =
148 currentScope.methodScope().recordInitializationStates(
149 mergedInfo = loopingContext.initsOnBreak);
153 //end of loop: either condition false or break
155 flowInfo.initsWhenFalse().unconditionalInits().mergedWith(
156 loopingContext.initsOnBreak.unconditionalInits());
157 mergedInitStateIndex =
158 currentScope.methodScope().recordInitializationStates(mergedInfo);
163 * For statement code generation
165 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
166 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
168 public void generateCode(BlockScope currentScope, CodeStream codeStream) {
170 if ((bits & IsReachableMASK) == 0) {
173 int pc = codeStream.position;
175 // generate the initializations
176 if (initializations != null) {
177 for (int i = 0, max = initializations.length; i < max; i++) {
178 initializations[i].generateCode(scope, codeStream);
183 Label actionLabel = new Label(codeStream);
184 Label conditionLabel = new Label(codeStream);
185 breakLabel.codeStream = codeStream;
186 if (continueLabel != null) {
187 continueLabel.codeStream = codeStream;
189 // jump over the actionBlock
190 if ((condition != null)
191 && (condition.constant == NotAConstant)
192 && !((action == null || action.isEmptyBlock()) && (increments == null))) {
193 int jumpPC = codeStream.position;
194 codeStream.goto_(conditionLabel);
195 codeStream.recordPositionsFrom(jumpPC, condition.sourceStart);
197 // generate the loop action
199 if (action != null) {
200 // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
201 if (condIfTrueInitStateIndex != -1) {
202 // insert all locals initialized inside the condition into the action generated prior to the condition
203 codeStream.addDefinitelyAssignedVariables(
205 condIfTrueInitStateIndex);
207 action.generateCode(scope, codeStream);
209 // continuation point
210 if (continueLabel != null) {
211 continueLabel.place();
212 // generate the increments for next iteration
213 if (increments != null) {
214 for (int i = 0, max = increments.length; i < max; i++) {
215 increments[i].generateCode(scope, codeStream);
220 // May loose some local variable initializations : affecting the local variable attributes
221 if (preCondInitStateIndex != -1) {
222 codeStream.removeNotDefinitelyAssignedVariables(
224 preCondInitStateIndex);
227 // generate the condition
228 conditionLabel.place();
229 if ((condition != null) && (condition.constant == NotAConstant)) {
230 condition.generateOptimizedBoolean(scope, codeStream, actionLabel, null, true);
232 if (continueLabel != null) {
233 codeStream.goto_(actionLabel);
238 // May loose some local variable initializations : affecting the local variable attributes
240 codeStream.exitUserScope(scope);
242 if (mergedInitStateIndex != -1) {
243 codeStream.removeNotDefinitelyAssignedVariables(
245 mergedInitStateIndex);
247 codeStream.recordPositionsFrom(pc, this.sourceStart);
250 public void resetStateForCodeGeneration() {
252 this.breakLabel.resetStateForCodeGeneration();
253 this.continueLabel.resetStateForCodeGeneration();
256 public void resolve(BlockScope upperScope) {
258 // use the scope that will hold the init declarations
259 scope = neededScope ? new BlockScope(upperScope) : upperScope;
260 if (initializations != null)
261 for (int i = 0, length = initializations.length; i < length; i++)
262 initializations[i].resolve(scope);
263 if (condition != null) {
264 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
265 condition.implicitWidening(type, type);
267 if (increments != null)
268 for (int i = 0, length = increments.length; i < length; i++)
269 increments[i].resolve(scope);
271 action.resolve(scope);
274 public String toString(int tab) {
276 String s = tabString(tab) + "for ("; //$NON-NLS-1$
278 s = s + " //--NO upperscope scope needed\n" + tabString(tab) + " "; //$NON-NLS-2$ //$NON-NLS-1$
280 if (initializations != null) {
281 for (int i = 0; i < initializations.length; i++) {
282 //nice only with expressions
283 s = s + initializations[i].toString(0);
284 if (i != (initializations.length - 1))
285 s = s + " , "; //$NON-NLS-1$
288 s = s + "; "; //$NON-NLS-1$
290 if (condition != null)
291 s = s + condition.toStringExpression();
292 s = s + "; "; //$NON-NLS-1$
294 if (increments != null) {
295 for (int i = 0; i < increments.length; i++) {
296 //nice only with expressions
297 s = s + increments[i].toString(0);
298 if (i != (increments.length - 1))
299 s = s + " , "; //$NON-NLS-1$
302 s = s + ") "; //$NON-NLS-1$
305 s = s + "{}"; //$NON-NLS-1$
307 s = s + "\n" + action.toString(tab + 1); //$NON-NLS-1$
311 public void traverse(
312 IAbstractSyntaxTreeVisitor visitor,
313 BlockScope blockScope) {
315 if (visitor.visit(this, blockScope)) {
316 if (initializations != null) {
317 int initializationsLength = initializations.length;
318 for (int i = 0; i < initializationsLength; i++)
319 initializations[i].traverse(visitor, scope);
322 if (condition != null)
323 condition.traverse(visitor, scope);
325 if (increments != null) {
326 int incrementsLength = increments.length;
327 for (int i = 0; i < incrementsLength; i++)
328 increments[i].traverse(visitor, scope);
332 action.traverse(visitor, scope);
334 visitor.endVisit(this, blockScope);