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 WhileStatement extends Statement {
24 public Expression condition;
26 public Statement action;
28 private Label breakLabel, continueLabel;
30 int preCondInitStateIndex = -1;
32 int condIfTrueInitStateIndex = -1;
34 int mergedInitStateIndex = -1;
36 public WhileStatement(Expression condition, Statement action, int s, int e) {
38 this.condition = condition;
44 public FlowInfo analyseCode(BlockScope currentScope,
45 FlowContext flowContext, FlowInfo flowInfo) {
47 breakLabel = new Label();
48 continueLabel = new Label();
50 Constant cst = this.condition.constant;
51 boolean isConditionTrue = cst != NotAConstant
52 && cst.booleanValue() == true;
53 boolean isConditionFalse = cst != NotAConstant
54 && cst.booleanValue() == false;
56 cst = this.condition.optimizedBooleanConstant();
57 boolean isConditionOptimizedTrue = cst != NotAConstant
58 && cst.booleanValue() == true;
59 boolean isConditionOptimizedFalse = cst != NotAConstant
60 && cst.booleanValue() == false;
62 preCondInitStateIndex = currentScope.methodScope()
63 .recordInitializationStates(flowInfo);
64 LoopingFlowContext condLoopContext;
65 FlowInfo postCondInfo = this.condition.analyseCode(currentScope,
66 (condLoopContext = new LoopingFlowContext(flowContext, this,
67 null, null, currentScope)), flowInfo);
69 LoopingFlowContext loopingContext;
72 // || (action.isEmptyBlock() &&
73 // currentScope.environment().options.complianceLevel <=
74 // CompilerOptions.JDK1_3)) {
75 // condLoopContext.complainOnFinalAssignmentsInLoop(currentScope,
77 // if (isConditionTrue) {
78 // return FlowInfo.DEAD_END;
80 // FlowInfo mergedInfo =
81 // postCondInfo.initsWhenFalse().unconditionalInits();
82 // if (isConditionOptimizedTrue){
83 // mergedInfo.setReachMode(FlowInfo.UNREACHABLE);
85 // mergedInitStateIndex =
86 // currentScope.methodScope().recordInitializationStates(mergedInfo);
90 // in case the condition was inlined to false, record the fact that
91 // there is no way to reach any
92 // statement inside the looping action
93 loopingContext = new LoopingFlowContext(flowContext, this, breakLabel,
94 continueLabel, currentScope);
95 if (isConditionFalse) {
96 actionInfo = FlowInfo.DEAD_END;
98 actionInfo = postCondInfo.initsWhenTrue().copy();
99 if (isConditionOptimizedFalse) {
100 actionInfo.setReachMode(FlowInfo.UNREACHABLE);
104 // for computing local var attributes
105 condIfTrueInitStateIndex = currentScope.methodScope()
106 .recordInitializationStates(postCondInfo.initsWhenTrue());
108 if (!actionInfo.complainIfUnreachable(action, currentScope, false)) {
109 actionInfo = action.analyseCode(currentScope, loopingContext,
113 // code generation can be optimized when no need to continue in the loop
114 if (!actionInfo.isReachable()
115 && !loopingContext.initsOnContinue.isReachable()) {
116 continueLabel = null;
118 // TODO: (philippe) should simplify in one Loop context
119 condLoopContext.complainOnFinalAssignmentsInLoop(currentScope,
121 loopingContext.complainOnFinalAssignmentsInLoop(currentScope,
128 if (isConditionOptimizedTrue) {
129 mergedInitStateIndex = currentScope.methodScope()
130 .recordInitializationStates(
131 mergedInfo = loopingContext.initsOnBreak);
135 // end of loop: either condition false or break
136 mergedInfo = postCondInfo.initsWhenFalse().unconditionalInits()
137 .mergedWith(loopingContext.initsOnBreak);
138 if (isConditionOptimizedTrue && continueLabel == null) {
139 mergedInfo.setReachMode(FlowInfo.UNREACHABLE);
141 mergedInitStateIndex = currentScope.methodScope()
142 .recordInitializationStates(mergedInfo);
147 * While code generation
149 * @param currentScope
150 * net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
152 * net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
154 // public void generateCode(BlockScope currentScope, CodeStream codeStream)
157 // if ((bits & IsReachableMASK) == 0) {
160 // int pc = codeStream.position;
161 // breakLabel.codeStream = codeStream;
163 // // generate condition
164 // if (continueLabel == null) {
165 // // no need to reverse condition
166 // if (condition.constant == NotAConstant) {
167 // condition.generateOptimizedBoolean(
175 // continueLabel.codeStream = codeStream;
176 // if (!(((condition.constant != NotAConstant)
177 // && (condition.constant.booleanValue() == true))
178 // || (action == null)
179 // || action.isEmptyBlock())) {
180 // int jumpPC = codeStream.position;
181 // codeStream.goto_(continueLabel);
182 // codeStream.recordPositionsFrom(jumpPC, condition.sourceStart);
185 // // generate the action
186 // Label actionLabel;
187 // (actionLabel = new Label(codeStream)).place();
188 // if (action != null) {
189 // // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for
190 // method appears incorrect
191 // if (condIfTrueInitStateIndex != -1) {
192 // // insert all locals initialized inside the condition into the action
193 // generated prior to the condition
194 // codeStream.addDefinitelyAssignedVariables(
196 // condIfTrueInitStateIndex);
198 // action.generateCode(currentScope, codeStream);
199 // // May loose some local variable initializations : affecting the local
200 // variable attributes
201 // if (preCondInitStateIndex != -1) {
202 // codeStream.removeNotDefinitelyAssignedVariables(
204 // preCondInitStateIndex);
208 // // output condition and branch back to the beginning of the repeated
210 // if (continueLabel != null) {
211 // continueLabel.place();
212 // condition.generateOptimizedBoolean(
219 // breakLabel.place();
221 // // May loose some local variable initializations : affecting the local
222 // variable attributes
223 // if (mergedInitStateIndex != -1) {
224 // codeStream.removeNotDefinitelyAssignedVariables(
226 // mergedInitStateIndex);
228 // codeStream.recordPositionsFrom(pc, this.sourceStart);
230 public void resetStateForCodeGeneration() {
231 if (this.breakLabel != null) {
232 this.breakLabel.resetStateForCodeGeneration();
234 if (this.continueLabel != null) {
235 this.continueLabel.resetStateForCodeGeneration();
239 public StringBuffer printStatement(int tab, StringBuffer output) {
241 printIndent(tab, output).append("while ("); //$NON-NLS-1$
242 condition.printExpression(0, output).append(')');
246 action.printStatement(tab + 1, output);
250 public void resolve(BlockScope scope) {
252 TypeBinding type = condition
253 .resolveTypeExpecting(scope, BooleanBinding);
254 condition.implicitWidening(type, type);
256 action.resolve(scope);
259 public String toString(int tab) {
261 String s = tabString(tab);
262 s = s + "while (" + condition.toStringExpression() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
264 s = s + " {} ;"; //$NON-NLS-1$
265 else if (action instanceof Block)
266 s = s + "\n" + action.toString(tab + 1); //$NON-NLS-1$
268 s = s + " {\n" + action.toString(tab + 1) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
272 public void traverse(ASTVisitor visitor, BlockScope blockScope) {
274 if (visitor.visit(this, blockScope)) {
275 condition.traverse(visitor, blockScope);
277 action.traverse(visitor, blockScope);
279 visitor.endVisit(this, blockScope);