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