6fa021a82d9a0bcc637c7aa217d5326d6a8fa97f
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / DoStatement.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.codegen.CodeStream;
15 import net.sourceforge.phpdt.internal.compiler.codegen.Label;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
17 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
18 import net.sourceforge.phpdt.internal.compiler.flow.LoopingFlowContext;
19 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
20 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
21 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
22
23 public class DoStatement extends Statement {
24
25         public Expression condition;
26         public Statement action;
27
28         private Label breakLabel, continueLabel;
29
30         // for local variables table attributes
31         int mergedInitStateIndex = -1;
32
33         public DoStatement(Expression condition, Statement action, int s, int e) {
34
35                 this.sourceStart = s;
36                 this.sourceEnd = e;
37                 this.condition = condition;
38                 this.action = action;
39         }
40
41         public FlowInfo analyseCode(
42                 BlockScope currentScope,
43                 FlowContext flowContext,
44                 FlowInfo flowInfo) {
45
46                 breakLabel = new Label();
47                 continueLabel = new Label();
48                 LoopingFlowContext loopingContext =
49                         new LoopingFlowContext(
50                                 flowContext,
51                                 this,
52                                 breakLabel,
53                                 continueLabel,
54                                 currentScope);
55
56                 Constant conditionConstant = condition.constant;
57                 Constant conditionalConstant = condition.conditionalConstant();
58                 boolean isFalseCondition =
59                         ((conditionConstant != NotAConstant)
60                                 && (conditionConstant.booleanValue() == false))
61                                 || ((conditionalConstant != NotAConstant)
62                                         && (conditionalConstant.booleanValue() == false));
63
64                 if ((action != null) && !action.isEmptyBlock()) {
65                         flowInfo = action.analyseCode(currentScope, loopingContext, flowInfo.copy());
66
67                         // code generation can be optimized when no need to continue in the loop
68                         if ((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable()) {
69                                 if ((loopingContext.initsOnContinue == FlowInfo.DeadEnd)
70                                         || loopingContext.initsOnContinue.isFakeReachable()) {
71                                         continueLabel = null;
72                                 } else {
73                                         flowInfo = loopingContext.initsOnContinue; // for condition
74                                         if (isFalseCondition) {
75                                                 //      continueLabel = null; - cannot nil the label since may be targeted already by 'continue' statements
76                                         } else {
77                                                 loopingContext.complainOnFinalAssignmentsInLoop(currentScope, flowInfo);
78                                         }
79                                 }
80                         } else {
81                                 if (isFalseCondition) {
82                                         //      continueLabel = null; - cannot nil the label since may be targeted already by 'continue' statements
83                                 } else {
84                                         loopingContext.complainOnFinalAssignmentsInLoop(currentScope, flowInfo);
85                                 }
86                         }
87                 }
88                 LoopingFlowContext condLoopContext;
89                 flowInfo =
90                         condition.analyseCode(
91                                 currentScope,
92                                 (condLoopContext =
93                                         new LoopingFlowContext(flowContext, this, null, null, currentScope)),
94                                 (action == null
95                                         ? flowInfo
96                                         : (flowInfo.mergedWith(loopingContext.initsOnContinue))));
97                 condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, flowInfo);
98
99                 // infinite loop
100                 FlowInfo mergedInfo;
101                 if ((condition.constant != NotAConstant)
102                         && (condition.constant.booleanValue() == true)) {
103                         mergedInfo = loopingContext.initsOnBreak;
104                         mergedInitStateIndex =
105                                 currentScope.methodScope().recordInitializationStates(mergedInfo);
106                         return mergedInfo;
107                 }
108
109                 // end of loop: either condition false or break
110                 mergedInfo =
111                         flowInfo.initsWhenFalse().unconditionalInits().mergedWith(
112                                 loopingContext.initsOnBreak);
113                 mergedInitStateIndex =
114                         currentScope.methodScope().recordInitializationStates(mergedInfo);
115                 return mergedInfo;
116         }
117
118         /**
119          * Do statement code generation
120          *
121          */
122         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
123
124                 if ((bits & IsReachableMASK) == 0) {
125                         return;
126                 }
127                 int pc = codeStream.position;
128
129                 // labels management
130                 Label actionLabel = new Label(codeStream);
131                 actionLabel.place();
132                 breakLabel.codeStream = codeStream;
133                 if (continueLabel != null) {
134                         continueLabel.codeStream = codeStream;
135                 }
136
137                 // generate action
138                 if (action != null) {
139                         action.generateCode(currentScope, codeStream);
140                 }
141                 // generate condition
142                 if (continueLabel != null) {
143                         continueLabel.place();
144                         condition.generateOptimizedBoolean(
145                                 currentScope,
146                                 codeStream,
147                                 actionLabel,
148                                 null,
149                                 true);
150                 }
151                 breakLabel.place();
152
153                 // May loose some local variable initializations : affecting the local variable attributes
154                 if (mergedInitStateIndex != -1) {
155                         codeStream.removeNotDefinitelyAssignedVariables(
156                                 currentScope,
157                                 mergedInitStateIndex);
158                 }
159                 codeStream.recordPositionsFrom(pc, this.sourceStart);
160
161         }
162
163         public void resetStateForCodeGeneration() {
164
165                 this.breakLabel.resetStateForCodeGeneration();
166                 this.continueLabel.resetStateForCodeGeneration();
167         }
168
169         public void resolve(BlockScope scope) {
170
171                 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
172                 condition.implicitWidening(type, type);
173                 if (action != null)
174                         action.resolve(scope);
175         }
176
177         public String toString(int tab) {
178
179                 String inFront, s = tabString(tab);
180                 inFront = s;
181                 s = s + "do"; //$NON-NLS-1$
182                 if (action == null)
183                         s = s + " {}\n"; //$NON-NLS-1$
184                 else if (action instanceof Block)
185                         s = s + "\n" + action.toString(tab + 1) + "\n"; //$NON-NLS-2$ //$NON-NLS-1$
186                 else
187                         s = s + " {\n" + action.toString(tab + 1) + ";}\n"; //$NON-NLS-1$ //$NON-NLS-2$
188                 s = s + inFront + "while (" + condition.toStringExpression() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
189                 return s;
190         }
191
192         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
193
194                 if (visitor.visit(this, scope)) {
195                         if (action != null) {
196                                 action.traverse(visitor, scope);
197                         }
198                         condition.traverse(visitor, scope);
199                 }
200                 visitor.endVisit(this, scope);
201         }
202 }