X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/WhileStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/WhileStatement.java index 80ff26a..ec7dd3e 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/WhileStatement.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/WhileStatement.java @@ -1,79 +1,281 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ package net.sourceforge.phpdt.internal.compiler.ast; -import java.util.List; -import java.util.ArrayList; +import net.sourceforge.phpdt.internal.compiler.ASTVisitor; +import net.sourceforge.phpdt.internal.compiler.codegen.Label; +import net.sourceforge.phpdt.internal.compiler.flow.FlowContext; +import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo; +import net.sourceforge.phpdt.internal.compiler.flow.LoopingFlowContext; +import net.sourceforge.phpdt.internal.compiler.impl.Constant; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; -/** - * A While statement. - * @author Matthieu Casanova - */ public class WhileStatement extends Statement { - /** The condition expression. */ - public Expression condition; - /** The action of the while. (it could be a block) */ - public Statement action; - - /** - * Create a While statement. - * @param condition the condition - * @param action the action - * @param sourceStart the starting offset - * @param sourceEnd the ending offset - */ - public WhileStatement(final Expression condition, - final Statement action, - final int sourceStart, - final int sourceEnd) { - super(sourceStart, sourceEnd); - this.condition = condition; - this.action = action; - } - - /** - * Return the object into String. - * @param tab how many tabs (not used here - * @return a String - */ - public String toString(final int tab) { - final String s = tabString(tab); - final StringBuffer buff = new StringBuffer(s).append("while ("); //$NON-NLS-1$ - buff.append(condition.toStringExpression()).append(")"); //$NON-NLS-1$ - if (action == null) { - buff.append(" {} ;"); //$NON-NLS-1$ - } else { - buff.append("\n").append(action.toString(tab + 1)); //$NON-NLS-1$ - } - return buff.toString(); - } - - /** - * Get the variables from outside (parameters, globals ...) - */ - public void getOutsideVariable(final List list) { - condition.getOutsideVariable(list); // todo: check if unuseful - if (action != null) { - action.getOutsideVariable(list); - } - } - - /** - * get the modified variables. - */ - public void getModifiedVariable(final List list) { - condition.getModifiedVariable(list); - if (action != null) { - action.getModifiedVariable(list); - } - } - - /** - * Get the variables used. - */ - public void getUsedVariable(final List list) { - condition.getUsedVariable(list); - if (action != null) { - action.getUsedVariable(list); - } - } + 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(); + + Constant cst = this.condition.constant; +// boolean isConditionTrue = cst != NotAConstant +// && cst.booleanValue() == true; + boolean isConditionFalse = cst != NotAConstant + && cst.booleanValue() == false; + + cst = this.condition.optimizedBooleanConstant(); + boolean isConditionOptimizedTrue = cst != NotAConstant + && cst.booleanValue() == true; + boolean isConditionOptimizedFalse = cst != NotAConstant + && cst.booleanValue() == false; + + preCondInitStateIndex = currentScope.methodScope() + .recordInitializationStates(flowInfo); + LoopingFlowContext condLoopContext; + FlowInfo postCondInfo = this.condition.analyseCode(currentScope, + (condLoopContext = new LoopingFlowContext(flowContext, this, + null, null, currentScope)), flowInfo); + + LoopingFlowContext loopingContext; + FlowInfo actionInfo; + // if (action == null + // || (action.isEmptyBlock() && + // currentScope.environment().options.complianceLevel <= + // CompilerOptions.JDK1_3)) { + // condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, + // postCondInfo); + // if (isConditionTrue) { + // return FlowInfo.DEAD_END; + // } else { + // FlowInfo mergedInfo = + // postCondInfo.initsWhenFalse().unconditionalInits(); + // if (isConditionOptimizedTrue){ + // mergedInfo.setReachMode(FlowInfo.UNREACHABLE); + // } + // 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); + if (isConditionFalse) { + actionInfo = FlowInfo.DEAD_END; + } else { + actionInfo = postCondInfo.initsWhenTrue().copy(); + if (isConditionOptimizedFalse) { + actionInfo.setReachMode(FlowInfo.UNREACHABLE); + } + } + + // for computing local var attributes + condIfTrueInitStateIndex = currentScope.methodScope() + .recordInitializationStates(postCondInfo.initsWhenTrue()); + + if (!actionInfo.complainIfUnreachable(action, currentScope, false)) { + actionInfo = action.analyseCode(currentScope, loopingContext, + actionInfo); + } + + // code generation can be optimized when no need to continue in the loop + if (!actionInfo.isReachable() + && !loopingContext.initsOnContinue.isReachable()) { + continueLabel = null; + } else { + // TODO: (philippe) should simplify in one Loop context + condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, + postCondInfo); + loopingContext.complainOnFinalAssignmentsInLoop(currentScope, + actionInfo); + } + // } + + // infinite loop + FlowInfo mergedInfo; + if (isConditionOptimizedTrue) { + mergedInitStateIndex = currentScope.methodScope() + .recordInitializationStates( + mergedInfo = loopingContext.initsOnBreak); + return mergedInfo; + } + + // end of loop: either condition false or break + mergedInfo = postCondInfo.initsWhenFalse().unconditionalInits() + .mergedWith(loopingContext.initsOnBreak); + if (isConditionOptimizedTrue && continueLabel == null) { + mergedInfo.setReachMode(FlowInfo.UNREACHABLE); + } + mergedInitStateIndex = currentScope.methodScope() + .recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * While code generation + * + * @param currentScope + * net.sourceforge.phpdt.internal.compiler.lookup.BlockScope + * @param codeStream + * net.sourceforge.phpdt.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.sourceStart); + // } + // } + // // 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.sourceStart); + // } + public void resetStateForCodeGeneration() { + if (this.breakLabel != null) { + this.breakLabel.resetStateForCodeGeneration(); + } + if (this.continueLabel != null) { + this.continueLabel.resetStateForCodeGeneration(); + } + } + + public StringBuffer printStatement(int tab, StringBuffer output) { + + printIndent(tab, output).append("while ("); //$NON-NLS-1$ + condition.printExpression(0, output).append(')'); + if (action == null) + output.append(';'); + else + action.printStatement(tab + 1, output); + return output; + } + + 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) { + + String s = tabString(tab); + s = s + "while (" + condition.toStringExpression() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + if (action == null) + s = s + " {} ;"; //$NON-NLS-1$ + else if (action instanceof Block) + s = s + "\n" + action.toString(tab + 1); //$NON-NLS-1$ + else + s = s + " {\n" + action.toString(tab + 1) + "}"; //$NON-NLS-2$ //$NON-NLS-1$ + return s; + } + + public void traverse(ASTVisitor visitor, BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + condition.traverse(visitor, blockScope); + if (action != null) + action.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } }