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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
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;
22 public class ForStatement extends Statement {
24 public Statement[] initializations;
26 public Expression condition;
28 public Statement[] increments;
30 public Statement action;
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
35 public boolean neededScope;
37 public BlockScope scope;
39 private Label breakLabel, continueLabel;
41 // for local variables table attributes
42 int preCondInitStateIndex = -1;
44 int condIfTrueInitStateIndex = -1;
46 int mergedInitStateIndex = -1;
48 public ForStatement(Statement[] initializations, Expression condition,
49 Statement[] increments, Statement action, boolean neededScope,
54 this.initializations = initializations;
55 this.condition = condition;
56 this.increments = increments;
58 this.neededScope = neededScope;
61 public FlowInfo analyseCode(BlockScope currentScope,
62 FlowContext flowContext, FlowInfo flowInfo) {
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,
75 preCondInitStateIndex = currentScope.methodScope()
76 .recordInitializationStates(flowInfo);
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);
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);
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);
101 // process the action
102 LoopingFlowContext loopingContext;
104 if (action == null) {
105 // || (action.isEmptyBlock() &&
106 // currentScope.environment().options.complianceLevel <=
107 // CompilerOptions.JDK1_3)) {
108 if (condLoopContext != null)
109 condLoopContext.complainOnFinalAssignmentsInLoop(scope,
111 if (isConditionTrue) {
112 return FlowInfo.DEAD_END;
114 if (isConditionFalse) {
115 continueLabel = null; // for(;false;p());
117 actionInfo = flowInfo.initsWhenTrue().copy();
118 loopingContext = new LoopingFlowContext(flowContext, this,
119 breakLabel, continueLabel, scope);
122 loopingContext = new LoopingFlowContext(flowContext, this,
123 breakLabel, continueLabel, scope);
124 FlowInfo initsWhenTrue = flowInfo.initsWhenTrue();
125 condIfTrueInitStateIndex = currentScope.methodScope()
126 .recordInitializationStates(initsWhenTrue);
128 if (isConditionFalse) {
129 actionInfo = FlowInfo.DEAD_END;
131 actionInfo = initsWhenTrue.copy();
132 if (isConditionOptimizedFalse) {
133 actionInfo.setReachMode(FlowInfo.UNREACHABLE);
136 if (!actionInfo.complainIfUnreachable(action, scope, false)) {
137 actionInfo = action.analyseCode(scope, loopingContext,
141 // code generation can be optimized when no need to continue in the
143 if (!actionInfo.isReachable()
144 && !loopingContext.initsOnContinue.isReachable()) {
145 continueLabel = null;
147 if (condLoopContext != null)
148 condLoopContext.complainOnFinalAssignmentsInLoop(scope,
150 loopingContext.complainOnFinalAssignmentsInLoop(scope,
152 actionInfo = actionInfo
153 .mergedWith(loopingContext.initsOnContinue
154 .unconditionalInits());
158 if ((continueLabel != null) && (increments != null)) {
159 LoopingFlowContext loopContext = new LoopingFlowContext(
160 flowContext, this, null, null, scope);
161 int i = 0, count = increments.length;
163 actionInfo = increments[i++].analyseCode(scope, loopContext,
165 loopContext.complainOnFinalAssignmentsInLoop(scope, actionInfo);
170 if (isConditionOptimizedTrue) {
171 mergedInitStateIndex = currentScope.methodScope()
172 .recordInitializationStates(
173 mergedInfo = loopingContext.initsOnBreak);
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);
183 mergedInitStateIndex = currentScope.methodScope()
184 .recordInitializationStates(mergedInfo);
189 * For statement code generation
191 * @param currentScope
192 * net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
194 * net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
196 // public void generateCode(BlockScope currentScope, CodeStream codeStream)
199 // if ((bits & IsReachableMASK) == 0) {
202 // int pc = codeStream.position;
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);
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;
218 // // jump over the actionBlock
219 // if ((condition != null)
220 // && (condition.constant == NotAConstant)
221 // && !((action == null || action.isEmptyBlock()) && (increments == null)))
223 // int jumpPC = codeStream.position;
224 // codeStream.goto_(conditionLabel);
225 // codeStream.recordPositionsFrom(jumpPC, condition.sourceStart);
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(
237 // condIfTrueInitStateIndex);
239 // action.generateCode(scope, codeStream);
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);
252 // // May loose some local variable initializations : affecting the local
253 // variable attributes
254 // if (preCondInitStateIndex != -1) {
255 // codeStream.removeNotDefinitelyAssignedVariables(
257 // preCondInitStateIndex);
260 // // generate the condition
261 // conditionLabel.place();
262 // if ((condition != null) && (condition.constant == NotAConstant)) {
263 // condition.generateOptimizedBoolean(scope, codeStream, actionLabel, null,
266 // if (continueLabel != null) {
267 // codeStream.goto_(actionLabel);
270 // breakLabel.place();
272 // // May loose some local variable initializations : affecting the local
273 // variable attributes
274 // if (neededScope) {
275 // codeStream.exitUserScope(scope);
277 // if (mergedInitStateIndex != -1) {
278 // codeStream.removeNotDefinitelyAssignedVariables(
280 // mergedInitStateIndex);
282 // codeStream.recordPositionsFrom(pc, this.sourceStart);
284 public void resetStateForCodeGeneration() {
285 if (this.breakLabel != null) {
286 this.breakLabel.resetStateForCodeGeneration();
288 if (this.continueLabel != null) {
289 this.continueLabel.resetStateForCodeGeneration();
293 public StringBuffer printStatement(int tab, StringBuffer output) {
295 printIndent(tab, output).append("for ("); //$NON-NLS-1$
297 if (initializations != null) {
298 for (int i = 0; i < initializations.length; i++) {
299 // nice only with expressions
301 output.append(", "); //$NON-NLS-1$
302 initializations[i].print(0, output);
305 output.append("; "); //$NON-NLS-1$
307 if (condition != null)
308 condition.printExpression(0, output);
309 output.append("; "); //$NON-NLS-1$
311 if (increments != null) {
312 for (int i = 0; i < increments.length; i++) {
314 output.append(", "); //$NON-NLS-1$
315 increments[i].print(0, output);
318 output.append(") "); //$NON-NLS-1$
324 action.printStatement(tab + 1, output); //$NON-NLS-1$
326 return output.append(';');
329 public void resolve(BlockScope upperScope) {
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,
339 condition.implicitWidening(type, type);
341 if (increments != null)
342 for (int i = 0, length = increments.length; i < length; i++)
343 increments[i].resolve(scope);
345 action.resolve(scope);
348 public String toString(int tab) {
350 String s = tabString(tab) + "for ("; //$NON-NLS-1$
353 + " //--NO upperscope scope needed\n" + tabString(tab) + " "; //$NON-NLS-2$ //$NON-NLS-1$
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$
364 s = s + "; "; //$NON-NLS-1$
366 if (condition != null)
367 s = s + condition.toStringExpression();
368 s = s + "; "; //$NON-NLS-1$
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$
379 s = s + ") "; //$NON-NLS-1$
382 s = s + "{}"; //$NON-NLS-1$
384 s = s + "\n" + action.toString(tab + 1); //$NON-NLS-1$
388 public void traverse(ASTVisitor visitor, BlockScope blockScope) {
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);
397 if (condition != null)
398 condition.traverse(visitor, scope);
400 if (increments != null) {
401 int incrementsLength = increments.length;
402 for (int i = 0; i < incrementsLength; i++)
403 increments[i].traverse(visitor, scope);
407 action.traverse(visitor, scope);
409 visitor.endVisit(this, blockScope);