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