Refactory: smarty.ui plugin.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / IfStatement.java
index f847463..39d5ae0 100644 (file)
+/*******************************************************************************
+ * 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;
 
-/**
- * @author Matthieu Casanova
- */
+import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
+import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
+import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
+import net.sourceforge.phpdt.internal.compiler.impl.Constant;
+import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
+import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
+
 public class IfStatement extends Statement {
 
-  public Expression condition;
-  public Statement statement;
-  public ElseIf[] elseifs;
-  public Else els;
-
-  /**
-   * Create a new If statement
-   * @param condition the condition
-   * @param statement a statement or a block of statements
-   * @param elseifs the elseifs
-   * @param els the else (or null)
-   * @param sourceStart the starting position
-   * @param sourceEnd the ending offset
-   */
-  public IfStatement(Expression condition,
-                     Statement statement,
-                     ElseIf[] elseifs,
-                     Else els,
-                     int sourceStart,
-                     int sourceEnd) {
-    super(sourceStart, sourceEnd);
-    this.condition = condition;
-    this.statement = statement;
-    this.elseifs = elseifs;
-    this.els = els;
-  }
-
-  /**
-   * Return the object into String.
-   * @param tab how many tabs (not used here
-   * @return a String
-   */
-  public String toString(int tab) {
-    final StringBuffer buff = new StringBuffer(tabString(tab));
-    buff.append("if (");
-    buff.append(condition.toStringExpression()).append(") ");
-    buff.append("\n");
-    buff.append(statement.toString(tab+1));
-    for (int i = 0; i < elseifs.length; i++) {
-      ElseIf elseif = elseifs[i];
-      buff.append(elseif.toString(tab+1));
-      buff.append("\n");
-    }
-    if (els != null) {
-      buff.append(els.toString(tab+1));
-      buff.append('\n');
-    }
-    return buff.toString();
-  }
+       // this class represents the case of only one statement in
+       // either else and/or then branches.
+
+       public Expression condition;
+
+       public Statement thenStatement;
+
+       public Statement elseStatement;
+
+       public Expression[] elseifConditions;
+
+       public Statement[] elseifStatements;
+
+       public boolean checkUnreachable;
+
+       boolean thenExit;
+
+       // for local variables table attributes
+       int thenInitStateIndex = -1;
+
+       int elseInitStateIndex = -1;
+
+       int mergedInitStateIndex = -1;
+
+       public IfStatement(Expression condition, Statement thenStatement, int s,
+                       int e) {
+
+               this.condition = condition;
+               this.thenStatement = thenStatement;
+               sourceStart = s;
+               sourceEnd = e;
+               checkUnreachable = true;
+       }
+
+       public IfStatement(Expression condition, Statement thenStatement,
+                       Statement elseStatement, int s, int e) {
+
+               this.condition = condition;
+               this.thenStatement = thenStatement;
+               this.elseStatement = elseStatement;
+               sourceEnd = e;
+               sourceStart = s;
+               checkUnreachable = true;
+       }
+
+       public FlowInfo analyseCode(BlockScope currentScope,
+                       FlowContext flowContext, FlowInfo flowInfo) {
+
+               // process the condition
+               flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo);
+
+               Constant cst = this.condition.optimizedBooleanConstant();
+               boolean isConditionOptimizedTrue = cst != NotAConstant
+                               && cst.booleanValue() == true;
+               boolean isConditionOptimizedFalse = cst != NotAConstant
+                               && cst.booleanValue() == false;
+
+               // process the THEN part
+               FlowInfo thenFlowInfo = flowInfo.initsWhenTrue().copy();
+               if (isConditionOptimizedFalse) {
+                       thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
+               }
+               if (this.thenStatement != null) {
+                       // Save info for code gen
+                       thenInitStateIndex = currentScope.methodScope()
+                                       .recordInitializationStates(thenFlowInfo);
+                       if (!thenFlowInfo.complainIfUnreachable(thenStatement,
+                                       currentScope, false)) {
+                               thenFlowInfo = thenStatement.analyseCode(currentScope,
+                                               flowContext, thenFlowInfo);
+                       }
+               }
+               ;
+               // optimizing the jump around the ELSE part
+               this.thenExit = !thenFlowInfo.isReachable();
+
+               // process the ELSE part
+               FlowInfo elseFlowInfo = flowInfo.initsWhenFalse().copy();
+               if (isConditionOptimizedTrue) {
+                       elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
+               }
+               if (this.elseStatement != null) {
+                       // Save info for code gen
+                       elseInitStateIndex = currentScope.methodScope()
+                                       .recordInitializationStates(elseFlowInfo);
+                       if (!elseFlowInfo.complainIfUnreachable(elseStatement,
+                                       currentScope, false)) {
+                               elseFlowInfo = elseStatement.analyseCode(currentScope,
+                                               flowContext, elseFlowInfo);
+                       }
+               }
+
+               boolean elseExit = !elseFlowInfo.isReachable();
+
+               // merge THEN & ELSE initializations
+               FlowInfo mergedInfo;
+               // if (isConditionOptimizedTrue){
+               // if (!this.thenExit) {
+               // mergedInfo = thenFlowInfo;
+               // } else {
+               // mergedInfo = elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
+               // }
+               //
+               // } else if (isConditionOptimizedFalse) {
+               // if (!elseExit) {
+               // mergedInfo = elseFlowInfo;
+               // } else {
+               // mergedInfo = thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
+               // }
+               //
+               // } else {
+               // mergedInfo =
+               // thenFlowInfo.mergedWith(elseFlowInfo.unconditionalInits());
+               // }
+               if (isConditionOptimizedTrue) {
+                       if (!this.thenExit) {
+                               mergedInfo = thenFlowInfo
+                                               .addPotentialInitializationsFrom(elseFlowInfo);
+                       } else {
+                               mergedInfo = elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
+                       }
+
+               } else if (isConditionOptimizedFalse) {
+                       if (!elseExit) {
+                               mergedInfo = elseFlowInfo
+                                               .addPotentialInitializationsFrom(thenFlowInfo);
+                       } else {
+                               mergedInfo = thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
+                       }
+
+               } else {
+                       mergedInfo = thenFlowInfo.mergedWith(elseFlowInfo
+                                       .unconditionalInits());
+               }
+
+               mergedInitStateIndex = currentScope.methodScope()
+                               .recordInitializationStates(mergedInfo);
+               return mergedInfo;
+       }
+
+       /**
+        * If 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 ((this.bits & IsReachableMASK) == 0) {
+       // return;
+       // }
+       // int pc = codeStream.position;
+       // Label endifLabel = new Label(codeStream);
+       //
+       // // optimizing the then/else part code gen
+       // Constant cst;
+       // boolean hasThenPart =
+       // !(((cst = this.condition.optimizedBooleanConstant()) != NotAConstant
+       // && cst.booleanValue() == false)
+       // || this.thenStatement == null
+       // || this.thenStatement.isEmptyBlock());
+       // boolean hasElsePart =
+       // !((cst != NotAConstant && cst.booleanValue() == true)
+       // || this.elseStatement == null
+       // || this.elseStatement.isEmptyBlock());
+       //
+       // if (hasThenPart) {
+       // Label falseLabel;
+       // // generate boolean condition
+       // this.condition.generateOptimizedBoolean(
+       // currentScope,
+       // codeStream,
+       // null,
+       // (falseLabel = new Label(codeStream)),
+       // true);
+       // // May loose some local variable initializations : affecting the local
+       // variable attributes
+       // if (thenInitStateIndex != -1) {
+       // codeStream.removeNotDefinitelyAssignedVariables(
+       // currentScope,
+       // thenInitStateIndex);
+       // codeStream.addDefinitelyAssignedVariables(currentScope,
+       // thenInitStateIndex);
+       // }
+       // // generate then statement
+       // this.thenStatement.generateCode(currentScope, codeStream);
+       // // jump around the else statement
+       // if (hasElsePart && !thenExit) {
+       // this.thenStatement.branchChainTo(endifLabel);
+       // int position = codeStream.position;
+       // codeStream.goto_(endifLabel);
+       // codeStream.updateLastRecordedEndPC(position);
+       // //goto is tagged as part of the thenAction block
+       // }
+       // falseLabel.place();
+       // } else {
+       // if (hasElsePart) {
+       // // generate boolean condition
+       // this.condition.generateOptimizedBoolean(
+       // currentScope,
+       // codeStream,
+       // endifLabel,
+       // null,
+       // true);
+       // } else {
+       // // generate condition side-effects
+       // this.condition.generateCode(currentScope, codeStream, false);
+       // codeStream.recordPositionsFrom(pc, this.sourceStart);
+       // }
+       // }
+       // // generate else statement
+       // if (hasElsePart) {
+       // // May loose some local variable initializations : affecting the local
+       // variable attributes
+       // if (elseInitStateIndex != -1) {
+       // codeStream.removeNotDefinitelyAssignedVariables(
+       // currentScope,
+       // elseInitStateIndex);
+       // codeStream.addDefinitelyAssignedVariables(currentScope,
+       // elseInitStateIndex);
+       // }
+       // this.elseStatement.generateCode(currentScope, codeStream);
+       // }
+       // endifLabel.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 StringBuffer printStatement(int indent, StringBuffer output) {
+
+               printIndent(indent, output).append("if ("); //$NON-NLS-1$
+               condition.printExpression(0, output).append(")\n"); //$NON-NLS-1$ 
+               thenStatement.printStatement(indent + 2, output);
+               if (elseStatement != null) {
+                       output.append('\n');
+                       printIndent(indent, output);
+                       output.append("else\n"); //$NON-NLS-1$
+                       elseStatement.printStatement(indent + 2, output);
+               }
+               return output;
+       }
+
+       public void resolve(BlockScope scope) {
+
+               TypeBinding type = condition
+                               .resolveTypeExpecting(scope, BooleanBinding);
+               condition.implicitWidening(type, type);
+               if (thenStatement != null)
+                       thenStatement.resolve(scope);
+               if (elseStatement != null)
+                       elseStatement.resolve(scope);
+       }
+
+       public String toString(int tab) {
+
+               String inFront, s = tabString(tab);
+               inFront = s;
+               s = s + "if (" + condition.toStringExpression() + ") \n"; //$NON-NLS-1$ //$NON-NLS-2$
+               s = s + thenStatement.toString(tab + 2) + ";"; //$NON-NLS-1$
+               if (elseStatement != null)
+                       s = s
+                                       + "\n" + inFront + "else\n" + elseStatement.toString(tab + 2) + ";"; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-3$
+               return s;
+       }
+
+       public void traverse(ASTVisitor visitor, BlockScope blockScope) {
+
+               if (visitor.visit(this, blockScope)) {
+                       condition.traverse(visitor, blockScope);
+                       if (thenStatement != null)
+                               thenStatement.traverse(visitor, blockScope);
+                       if (elseStatement != null)
+                               elseStatement.traverse(visitor, blockScope);
+               }
+               visitor.endVisit(this, blockScope);
+       }
 }