improved PHP parser
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / internal / compiler / ast / IfStatement.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpeclipse.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
14 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
16 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
17 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
18 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
19
20 public class IfStatement extends Statement {
21         
22         //this class represents the case of only one statement in 
23         //either else and/or then branches.
24
25         public Expression condition;
26         public Statement thenStatement;
27         public Statement elseStatement;
28
29         boolean thenExit;
30
31         // for local variables table attributes
32         int thenInitStateIndex = -1;
33         int elseInitStateIndex = -1;
34         int mergedInitStateIndex = -1;
35
36         public IfStatement(
37                 Expression condition,
38                 Statement thenStatement,
39                 int s,
40                 int e) {
41
42                 this.condition = condition;
43                 this.thenStatement = thenStatement;
44                 sourceStart = s;
45                 sourceEnd = e;
46         }
47
48         public IfStatement(
49                 Expression condition,
50                 Statement thenStatement,
51                 Statement elseStatement,
52                 int s,
53                 int e) {
54
55                 this.condition = condition;
56                 this.thenStatement = thenStatement;
57                 this.elseStatement = elseStatement;
58                 sourceEnd = e;
59                 sourceStart = s;
60         }
61
62         public FlowInfo analyseCode(
63                 BlockScope currentScope,
64                 FlowContext flowContext,
65                 FlowInfo flowInfo) {
66
67                 // process the condition
68                 flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo);
69
70                 Constant cst = this.condition.optimizedBooleanConstant();
71                 boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true;
72                 boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false;
73                 
74                 // process the THEN part
75                 FlowInfo thenFlowInfo = flowInfo.initsWhenTrue().copy();
76                 if (isConditionOptimizedFalse) {
77                         thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE); 
78                 }
79                 if (this.thenStatement != null) {
80                         // Save info for code gen
81                         thenInitStateIndex =
82                                 currentScope.methodScope().recordInitializationStates(thenFlowInfo);
83                         if (!thenFlowInfo.complainIfUnreachable(thenStatement, currentScope, false)) {
84                                 thenFlowInfo =
85                                         thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo);
86                         }
87                 };
88                 // optimizing the jump around the ELSE part
89                 this.thenExit = !thenFlowInfo.isReachable();
90
91                 // process the ELSE part
92                 FlowInfo elseFlowInfo = flowInfo.initsWhenFalse().copy();
93                 if (isConditionOptimizedTrue) {
94                         elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); 
95                 }
96                 if (this.elseStatement != null) {
97                         // Save info for code gen
98                         elseInitStateIndex =
99                                 currentScope.methodScope().recordInitializationStates(elseFlowInfo);
100                         if (!elseFlowInfo.complainIfUnreachable(elseStatement, currentScope, false)) {
101                                 elseFlowInfo =
102                                         elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo);
103                         }
104                 }
105
106                 boolean elseExit = !elseFlowInfo.isReachable();
107                 
108                 // merge THEN & ELSE initializations
109                 FlowInfo mergedInfo;
110 //              if (isConditionOptimizedTrue){
111 //                      if (!this.thenExit) {
112 //                              mergedInfo = thenFlowInfo;
113 //                      } else {
114 //                              mergedInfo = elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
115 //                      }
116 //
117 //              } else if (isConditionOptimizedFalse) {
118 //                      if (!elseExit) {
119 //                              mergedInfo = elseFlowInfo;
120 //                      } else {
121 //                              mergedInfo = thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
122 //                      }
123 //
124 //              } else {
125 //                      mergedInfo = thenFlowInfo.mergedWith(elseFlowInfo.unconditionalInits());
126 //              }
127                 if (isConditionOptimizedTrue){
128                         if (!this.thenExit) {
129                                 mergedInfo = thenFlowInfo.addPotentialInitializationsFrom(elseFlowInfo);
130                         } else {
131                                 mergedInfo = elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
132                         }
133
134                 } else if (isConditionOptimizedFalse) {
135                         if (!elseExit) {
136                                 mergedInfo = elseFlowInfo.addPotentialInitializationsFrom(thenFlowInfo);
137                         } else {
138                                 mergedInfo = thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
139                         }
140
141                 } else {
142                         mergedInfo = thenFlowInfo.mergedWith(elseFlowInfo.unconditionalInits());
143                 }
144
145                 mergedInitStateIndex =
146                         currentScope.methodScope().recordInitializationStates(mergedInfo);
147                 return mergedInfo;
148         }
149
150         /**
151          * If code generation
152          *
153          * @param currentScope net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
154          * @param codeStream net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
155          */
156 //      public void generateCode(BlockScope currentScope, CodeStream codeStream) {
157 //
158 //              if ((this.bits & IsReachableMASK) == 0) {
159 //                      return;
160 //              }
161 //              int pc = codeStream.position;
162 //              Label endifLabel = new Label(codeStream);
163 //
164 //              // optimizing the then/else part code gen
165 //              Constant cst;
166 //              boolean hasThenPart = 
167 //                      !(((cst = this.condition.optimizedBooleanConstant()) != NotAConstant
168 //                                      && cst.booleanValue() == false)
169 //                              || this.thenStatement == null
170 //                              || this.thenStatement.isEmptyBlock());
171 //              boolean hasElsePart =
172 //                      !((cst != NotAConstant && cst.booleanValue() == true)
173 //                              || this.elseStatement == null
174 //                              || this.elseStatement.isEmptyBlock());
175 //
176 //              if (hasThenPart) {
177 //                      Label falseLabel;
178 //                      // generate boolean condition
179 //                      this.condition.generateOptimizedBoolean(
180 //                              currentScope,
181 //                              codeStream,
182 //                              null,
183 //                              (falseLabel = new Label(codeStream)),
184 //                              true);
185 //                      // May loose some local variable initializations : affecting the local variable attributes
186 //                      if (thenInitStateIndex != -1) {
187 //                              codeStream.removeNotDefinitelyAssignedVariables(
188 //                                      currentScope,
189 //                                      thenInitStateIndex);
190 //                              codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex);
191 //                      }
192 //                      // generate then statement
193 //                      this.thenStatement.generateCode(currentScope, codeStream);
194 //                      // jump around the else statement
195 //                      if (hasElsePart && !thenExit) {
196 //                              this.thenStatement.branchChainTo(endifLabel);
197 //                              int position = codeStream.position;
198 //                              codeStream.goto_(endifLabel);
199 //                              codeStream.updateLastRecordedEndPC(position);
200 //                              //goto is tagged as part of the thenAction block
201 //                      }
202 //                      falseLabel.place();
203 //              } else {
204 //                      if (hasElsePart) {
205 //                              // generate boolean condition
206 //                              this.condition.generateOptimizedBoolean(
207 //                                      currentScope,
208 //                                      codeStream,
209 //                                      endifLabel,
210 //                                      null,
211 //                                      true);
212 //                      } else {
213 //                              // generate condition side-effects
214 //                              this.condition.generateCode(currentScope, codeStream, false);
215 //                              codeStream.recordPositionsFrom(pc, this.sourceStart);
216 //                      }
217 //              }
218 //              // generate else statement
219 //              if (hasElsePart) {
220 //                      // May loose some local variable initializations : affecting the local variable attributes
221 //                      if (elseInitStateIndex != -1) {
222 //                              codeStream.removeNotDefinitelyAssignedVariables(
223 //                                      currentScope,
224 //                                      elseInitStateIndex);
225 //                              codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex);
226 //                      }
227 //                      this.elseStatement.generateCode(currentScope, codeStream);
228 //              }
229 //              endifLabel.place();
230 //              // May loose some local variable initializations : affecting the local variable attributes
231 //              if (mergedInitStateIndex != -1) {
232 //                      codeStream.removeNotDefinitelyAssignedVariables(
233 //                              currentScope,
234 //                              mergedInitStateIndex);
235 //              }
236 //              codeStream.recordPositionsFrom(pc, this.sourceStart);
237 //      }
238         public StringBuffer printStatement(int indent, StringBuffer output) {
239
240                 printIndent(indent, output).append("if ("); //$NON-NLS-1$
241                 condition.printExpression(0, output).append(")\n");     //$NON-NLS-1$ 
242                 thenStatement.printStatement(indent + 2, output);
243                 if (elseStatement != null) {
244                         output.append('\n');
245                         printIndent(indent, output);
246                         output.append("else\n"); //$NON-NLS-1$
247                         elseStatement.printStatement(indent + 2, output);
248                 }
249                 return output;
250         }
251         public void resolve(BlockScope scope) {
252
253                 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
254                 condition.implicitWidening(type, type);
255                 if (thenStatement != null)
256                         thenStatement.resolve(scope);
257                 if (elseStatement != null)
258                         elseStatement.resolve(scope);
259         }
260
261         public String toString(int tab) {
262
263                 String inFront, s = tabString(tab);
264                 inFront = s;
265                 s = s + "if (" + condition.toStringExpression() + ") \n";       //$NON-NLS-1$ //$NON-NLS-2$
266                 s = s + thenStatement.toString(tab + 2) + ";"; //$NON-NLS-1$
267                 if (elseStatement != null)
268                         s = s + "\n" + inFront + "else\n" + elseStatement.toString(tab + 2) + ";"; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-3$
269                 return s;
270         }
271
272         public void traverse(
273             ASTVisitor visitor,
274                 BlockScope blockScope) {
275
276                 if (visitor.visit(this, blockScope)) {
277                         condition.traverse(visitor, blockScope);
278                         if (thenStatement != null)
279                                 thenStatement.traverse(visitor, blockScope);
280                         if (elseStatement != null)
281                                 elseStatement.traverse(visitor, blockScope);
282                 }
283                 visitor.endVisit(this, blockScope);
284         }
285 }