package org.eclipse.jdt.internal.compiler.ast; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor; | |
import org.eclipse.jdt.internal.compiler.impl.*; | |
import org.eclipse.jdt.internal.compiler.codegen.*; | |
import org.eclipse.jdt.internal.compiler.flow.*; | |
import org.eclipse.jdt.internal.compiler.lookup.*; | |
public class WhileStatement extends Statement { | |
public Expression condition; | |
public Statement action; | |
private Label breakLabel, continueLabel; | |
int preCondInitStateIndex = -1; | |
int condIfTrueInitStateIndex = -1; | |
int mergedInitStateIndex = -1; | |
public WhileStatement(Expression condition, Statement action,int s,int e) { | |
this.condition = condition; | |
this.action = action; | |
sourceStart = s; | |
sourceEnd = e; | |
} | |
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { | |
breakLabel = new Label(); | |
continueLabel = new Label(); | |
preCondInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); | |
LoopingFlowContext condLoopContext; | |
FlowInfo postCondInfo = condition.analyseCode( | |
currentScope, | |
(condLoopContext = new LoopingFlowContext(flowContext, this, null, null, currentScope)), | |
flowInfo); | |
LoopingFlowContext loopingContext; | |
if ((action == null) || action.isEmptyBlock()) { | |
condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo); | |
if ((condition.constant != NotAConstant) && (condition.constant.booleanValue() == true)) { | |
return FlowInfo.DeadEnd; | |
} else { | |
FlowInfo mergedInfo = postCondInfo.initsWhenFalse().unconditionalInits(); | |
mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); | |
return mergedInfo; | |
} | |
} else { | |
// in case the condition was inlined to false, record the fact that there is no way to reach any | |
// statement inside the looping action | |
loopingContext = new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, currentScope); | |
FlowInfo actionInfo = | |
((condition.constant != Constant.NotAConstant) && (condition.constant.booleanValue() == false)) ? | |
FlowInfo.DeadEnd : | |
postCondInfo.initsWhenTrue().copy(); | |
// for computing local var attributes | |
condIfTrueInitStateIndex = currentScope.methodScope().recordInitializationStates(postCondInfo.initsWhenTrue()); | |
if (!actionInfo.complainIfUnreachable(action, currentScope)){ | |
actionInfo = action.analyseCode(currentScope, loopingContext, actionInfo); | |
} | |
// code generation can be optimized when no need to continue in the loop | |
if (((actionInfo == FlowInfo.DeadEnd) || actionInfo.isFakeReachable()) | |
&& ((loopingContext.initsOnContinue == FlowInfo.DeadEnd) || loopingContext.initsOnContinue.isFakeReachable())){ | |
continueLabel = null; | |
} else { | |
condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo); | |
loopingContext.complainOnFinalAssignmentsInLoop(currentScope, actionInfo); | |
} | |
} | |
// infinite loop | |
FlowInfo mergedInfo; | |
if ((condition.constant != Constant.NotAConstant) && (condition.constant.booleanValue() == true)) { | |
mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo = loopingContext.initsOnBreak); | |
return mergedInfo; | |
} | |
// end of loop: either condition false or break | |
mergedInfo = postCondInfo.initsWhenFalse().unconditionalInits().mergedWith(loopingContext.initsOnBreak); | |
mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); | |
return mergedInfo; | |
} | |
/** | |
* While code generation | |
* | |
* @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope | |
* @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream | |
*/ | |
public void generateCode(BlockScope currentScope, CodeStream codeStream) { | |
if ((bits & IsReachableMASK) == 0) { | |
return; | |
} | |
int pc = codeStream.position; | |
breakLabel.codeStream = codeStream; | |
// generate condition | |
if (continueLabel == null){ | |
// no need to reverse condition | |
if (condition.constant == NotAConstant){ | |
condition.generateOptimizedBoolean(currentScope, codeStream, null, breakLabel, true); | |
} | |
} else { | |
continueLabel.codeStream = codeStream; | |
if (!(((condition.constant != NotAConstant) && (condition.constant.booleanValue() == true)) || (action == null) || action.isEmptyBlock())){ | |
int jumpPC = codeStream.position; | |
codeStream.goto_(continueLabel); | |
codeStream.recordPositionsFrom(jumpPC, condition); | |
} | |
} | |
// generate the action | |
Label actionLabel; | |
(actionLabel = new Label(codeStream)).place(); | |
if (action != null){ | |
// Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect | |
if (condIfTrueInitStateIndex != -1){ // insert all locals initialized inside the condition into the action generated prior to the condition | |
codeStream.addDefinitelyAssignedVariables(currentScope, condIfTrueInitStateIndex); | |
} | |
action.generateCode(currentScope, codeStream); | |
// May loose some local variable initializations : affecting the local variable attributes | |
if (preCondInitStateIndex != -1) { | |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, preCondInitStateIndex); | |
} | |
} | |
// output condition and branch back to the beginning of the repeated action | |
if (continueLabel != null){ | |
continueLabel.place(); | |
condition.generateOptimizedBoolean(currentScope, codeStream, actionLabel, null, true); | |
} | |
breakLabel.place(); | |
// May loose some local variable initializations : affecting the local variable attributes | |
if (mergedInitStateIndex != -1) { | |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
} | |
public void resolve(BlockScope scope) { | |
TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding); | |
condition.implicitWidening(type, type); | |
if (action != null) | |
action.resolve(scope); | |
} | |
public String toString(int tab){ | |
/* slow code */ | |
String s = tabString(tab) ; | |
s = s + "while ("/*nonNLS*/ + condition.toStringExpression() + ")"/*nonNLS*/; | |
if (action == null) | |
s = s + " {} ;"/*nonNLS*/; | |
else | |
if (action instanceof Block) | |
s = s + "\n"/*nonNLS*/ + action.toString(tab+1) ; | |
else | |
s = s + " {\n"/*nonNLS*/ + action.toString(tab+1) + "}"/*nonNLS*/ ; | |
return s;} | |
public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope blockScope) { | |
if (visitor.visit(this, blockScope)) { | |
condition.traverse(visitor, blockScope); | |
if (action != null) | |
action.traverse(visitor, blockScope); | |
} | |
visitor.endVisit(this, blockScope); | |
} | |
} |