first scanner /parser copied from the jdt java version
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / WhileStatement.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.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.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.impl.*;
15 import net.sourceforge.phpdt.internal.compiler.codegen.*;
16 import net.sourceforge.phpdt.internal.compiler.flow.*;
17 import net.sourceforge.phpdt.internal.compiler.lookup.*;
18
19 public class WhileStatement extends Statement {
20         
21         public Expression condition;
22         public Statement action;
23         private Label breakLabel, continueLabel;
24         int preCondInitStateIndex = -1;
25         int condIfTrueInitStateIndex = -1;
26         int mergedInitStateIndex = -1;
27
28         public WhileStatement(Expression condition, Statement action, int s, int e) {
29
30                 this.condition = condition;
31                 this.action = action;
32                 sourceStart = s;
33                 sourceEnd = e;
34         }
35
36         public FlowInfo analyseCode(
37                 BlockScope currentScope,
38                 FlowContext flowContext,
39                 FlowInfo flowInfo) {
40
41                 breakLabel = new Label();
42                 continueLabel = new Label();
43
44                 preCondInitStateIndex =
45                         currentScope.methodScope().recordInitializationStates(flowInfo);
46                 LoopingFlowContext condLoopContext;
47                 FlowInfo postCondInfo =
48                         condition.analyseCode(
49                                 currentScope,
50                                 (condLoopContext =
51                                         new LoopingFlowContext(flowContext, this, null, null, currentScope)),
52                                 flowInfo);
53
54                 LoopingFlowContext loopingContext;
55                 if ((action == null) || action.isEmptyBlock()) {
56                         condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo);
57                         if ((condition.constant != NotAConstant)
58                                 && (condition.constant.booleanValue() == true)) {
59                                 return FlowInfo.DeadEnd;
60                         } else {
61                                 FlowInfo mergedInfo = postCondInfo.initsWhenFalse().unconditionalInits();
62                                 mergedInitStateIndex =
63                                         currentScope.methodScope().recordInitializationStates(mergedInfo);
64                                 return mergedInfo;
65                         }
66                 } else {
67                         // in case the condition was inlined to false, record the fact that there is no way to reach any 
68                         // statement inside the looping action
69                         loopingContext =
70                                 new LoopingFlowContext(
71                                         flowContext,
72                                         this,
73                                         breakLabel,
74                                         continueLabel,
75                                         currentScope);
76                         FlowInfo actionInfo =
77                                 ((condition.constant != Constant.NotAConstant)
78                                         && (condition.constant.booleanValue() == false))
79                                         ? FlowInfo.DeadEnd
80                                         : postCondInfo.initsWhenTrue().copy();
81
82                         // for computing local var attributes
83                         condIfTrueInitStateIndex =
84                                 currentScope.methodScope().recordInitializationStates(
85                                         postCondInfo.initsWhenTrue());
86
87                         if (!actionInfo.complainIfUnreachable(action, currentScope)) {
88                                 actionInfo = action.analyseCode(currentScope, loopingContext, actionInfo);
89                         }
90
91                         // code generation can be optimized when no need to continue in the loop
92                         if (((actionInfo == FlowInfo.DeadEnd) || actionInfo.isFakeReachable())
93                                 && ((loopingContext.initsOnContinue == FlowInfo.DeadEnd)
94                                         || loopingContext.initsOnContinue.isFakeReachable())) {
95                                 continueLabel = null;
96                         } else {
97                                 condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo);
98                                 loopingContext.complainOnFinalAssignmentsInLoop(currentScope, actionInfo);
99                         }
100                 }
101
102                 // infinite loop
103                 FlowInfo mergedInfo;
104                 if ((condition.constant != Constant.NotAConstant)
105                         && (condition.constant.booleanValue() == true)) {
106                         mergedInitStateIndex =
107                                 currentScope.methodScope().recordInitializationStates(
108                                         mergedInfo = loopingContext.initsOnBreak);
109                         return mergedInfo;
110                 }
111
112                 // end of loop: either condition false or break
113                 mergedInfo =
114                         postCondInfo.initsWhenFalse().unconditionalInits().mergedWith(
115                                 loopingContext.initsOnBreak);
116                 mergedInitStateIndex =
117                         currentScope.methodScope().recordInitializationStates(mergedInfo);
118                 return mergedInfo;
119         }
120
121         /**
122          * While code generation
123          *
124          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
125          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
126          */
127         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
128
129                 if ((bits & IsReachableMASK) == 0) {
130                         return;
131                 }
132                 int pc = codeStream.position;
133                 breakLabel.codeStream = codeStream;
134
135                 // generate condition
136                 if (continueLabel == null) {
137                         // no need to reverse condition
138                         if (condition.constant == NotAConstant) {
139                                 condition.generateOptimizedBoolean(
140                                         currentScope,
141                                         codeStream,
142                                         null,
143                                         breakLabel,
144                                         true);
145                         }
146                 } else {
147                         continueLabel.codeStream = codeStream;
148                         if (!(((condition.constant != NotAConstant)
149                                 && (condition.constant.booleanValue() == true))
150                                 || (action == null)
151                                 || action.isEmptyBlock())) {
152                                 int jumpPC = codeStream.position;
153                                 codeStream.goto_(continueLabel);
154                                 codeStream.recordPositionsFrom(jumpPC, condition.sourceStart);
155                         }
156                 }
157                 // generate the action
158                 Label actionLabel;
159                 (actionLabel = new Label(codeStream)).place();
160                 if (action != null) {
161                         // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
162                         if (condIfTrueInitStateIndex != -1) {
163                                 // insert all locals initialized inside the condition into the action generated prior to the condition
164                                 codeStream.addDefinitelyAssignedVariables(
165                                         currentScope,
166                                         condIfTrueInitStateIndex);
167                         }
168                         action.generateCode(currentScope, codeStream);
169                         // May loose some local variable initializations : affecting the local variable attributes
170                         if (preCondInitStateIndex != -1) {
171                                 codeStream.removeNotDefinitelyAssignedVariables(
172                                         currentScope,
173                                         preCondInitStateIndex);
174                         }
175
176                 }
177                 // output condition and branch back to the beginning of the repeated action
178                 if (continueLabel != null) {
179                         continueLabel.place();
180                         condition.generateOptimizedBoolean(
181                                 currentScope,
182                                 codeStream,
183                                 actionLabel,
184                                 null,
185                                 true);
186                 }
187                 breakLabel.place();
188
189                 // May loose some local variable initializations : affecting the local variable attributes
190                 if (mergedInitStateIndex != -1) {
191                         codeStream.removeNotDefinitelyAssignedVariables(
192                                 currentScope,
193                                 mergedInitStateIndex);
194                 }
195                 codeStream.recordPositionsFrom(pc, this.sourceStart);
196         }
197
198         public void resetStateForCodeGeneration() {
199
200                 this.breakLabel.resetStateForCodeGeneration();
201                 this.continueLabel.resetStateForCodeGeneration();
202         }
203
204         public void resolve(BlockScope scope) {
205
206                 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
207                 condition.implicitWidening(type, type);
208                 if (action != null)
209                         action.resolve(scope);
210         }
211
212         public String toString(int tab) {
213
214                 String s = tabString(tab);
215                 s = s + "while (" + condition.toStringExpression() + ")";       //$NON-NLS-1$ //$NON-NLS-2$
216                 if (action == null)
217                         s = s + " {} ;"; //$NON-NLS-1$ 
218                 else if (action instanceof Block)
219                         s = s + "\n" + action.toString(tab + 1); //$NON-NLS-1$
220                 else
221                         s = s + " {\n" + action.toString(tab + 1) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
222                 return s;
223         }
224
225         public void traverse(
226                 IAbstractSyntaxTreeVisitor visitor,
227                 BlockScope blockScope) {
228
229                 if (visitor.visit(this, blockScope)) {
230                         condition.traverse(visitor, blockScope);
231                         if (action != null)
232                                 action.traverse(visitor, blockScope);
233                 }
234                 visitor.endVisit(this, blockScope);
235         }
236 }