*** empty log message ***
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / AND_AND_Expression.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.impl.Constant;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
20
21 //dedicated treatment for the &&
22 public class AND_AND_Expression extends BinaryExpression {
23
24         int rightInitStateIndex = -1;
25         int mergedInitStateIndex = -1;
26
27         public AND_AND_Expression(Expression left, Expression right, int operator) {
28                 super(left, right, operator);
29         }
30
31         public FlowInfo analyseCode(
32                 BlockScope currentScope,
33                 FlowContext flowContext,
34                 FlowInfo flowInfo) {
35
36                 Constant opConstant = left.conditionalConstant();
37                 if (opConstant != NotAConstant) {
38                         if (opConstant.booleanValue() == true) {
39                                 // TRUE && anything
40                                  // need to be careful of scenario:
41                                 //              (x && y) && !z, if passing the left info to the right, it would be swapped by the !
42                                 FlowInfo mergedInfo = left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); 
43                                 mergedInfo = right.analyseCode(currentScope, flowContext, mergedInfo);
44                                 mergedInitStateIndex =
45                                         currentScope.methodScope().recordInitializationStates(mergedInfo);
46                                 return mergedInfo;
47                         }
48                 }
49                 FlowInfo leftInfo = left.analyseCode(currentScope, flowContext, flowInfo);
50                  // need to be careful of scenario:
51                 //              (x && y) && !z, if passing the left info to the right, it would be swapped by the !
52                 FlowInfo rightInfo = leftInfo.initsWhenTrue().unconditionalInits().copy();
53                 if (opConstant != NotAConstant && opConstant.booleanValue() == false) rightInfo.markAsFakeReachable(true);
54
55                 rightInitStateIndex =
56                         currentScope.methodScope().recordInitializationStates(rightInfo);
57                 rightInfo = right.analyseCode(currentScope, flowContext, rightInfo);
58                 FlowInfo mergedInfo =
59                         FlowInfo.conditional(
60                                 rightInfo.initsWhenTrue().copy(),
61                                 leftInfo.initsWhenFalse().copy().unconditionalInits().mergedWith(
62                                         rightInfo.initsWhenFalse().copy().unconditionalInits()));
63                 mergedInitStateIndex =
64                         currentScope.methodScope().recordInitializationStates(mergedInfo);
65                 return mergedInfo;
66         }
67
68         /**
69          * Code generation for a binary operation
70          */
71         public void generateCode(
72                 BlockScope currentScope,
73                 CodeStream codeStream,
74                 boolean valueRequired) {
75                         
76                 int pc = codeStream.position;
77                 Label falseLabel, endLabel;
78                 if (constant != Constant.NotAConstant) {
79                         // inlined value
80                         if (valueRequired)
81                                 codeStream.generateConstant(constant, implicitConversion);
82                         codeStream.recordPositionsFrom(pc, this.sourceStart);
83                         return;
84                 }
85                 bits |= OnlyValueRequiredMASK;
86                 generateOptimizedBoolean(
87                         currentScope,
88                         codeStream,
89                         null,
90                         (falseLabel = new Label(codeStream)),
91                         valueRequired);
92                 /* improving code gen for such a case: boolean b = i < 0 && false
93                  * since the label has never been used, we have the inlined value on the stack. */
94                 if (falseLabel.hasForwardReferences()) {
95                         if (valueRequired) {
96                                 codeStream.iconst_1();
97                                 if ((bits & ValueForReturnMASK) != 0) {
98                                         codeStream.ireturn();
99                                         falseLabel.place();
100                                         codeStream.iconst_0();
101                                 } else {
102                                         codeStream.goto_(endLabel = new Label(codeStream));
103                                         codeStream.decrStackSize(1);
104                                         falseLabel.place();
105                                         codeStream.iconst_0();
106                                         endLabel.place();
107                                 }
108                         } else {
109                                 falseLabel.place();
110                         }
111                 }
112                 if (valueRequired) {
113                         codeStream.generateImplicitConversion(implicitConversion);
114                 }
115                 codeStream.recordPositionsFrom(pc, this.sourceStart);
116         }
117
118         /**
119          * Boolean operator code generation
120          *      Optimized operations are: &&
121          */
122         public void generateOptimizedBoolean(
123                 BlockScope currentScope,
124                 CodeStream codeStream,
125                 Label trueLabel,
126                 Label falseLabel,
127                 boolean valueRequired) {
128                 if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
129                         super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
130                         return;
131                 }
132                 int pc = codeStream.position;
133                 Constant condConst;
134                 if ((condConst = left.conditionalConstant()) != NotAConstant) {
135                         if (condConst.booleanValue() == true) {
136                                 // <something equivalent to true> && x
137                                 left.generateOptimizedBoolean(
138                                         currentScope,
139                                         codeStream,
140                                         trueLabel,
141                                         falseLabel,
142                                         false);
143                                 if (rightInitStateIndex != -1) {
144                                         codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
145                                 }
146                                 if ((bits & OnlyValueRequiredMASK) != 0) {
147                                         right.generateCode(currentScope, codeStream, valueRequired);
148                                 } else {
149                                         right.generateOptimizedBoolean(
150                                                 currentScope,
151                                                 codeStream,
152                                                 trueLabel,
153                                                 falseLabel,
154                                                 valueRequired);
155                                 }
156                         } else {
157                                 // <something equivalent to false> && x
158                                 left.generateOptimizedBoolean(
159                                         currentScope,
160                                         codeStream,
161                                         trueLabel,
162                                         falseLabel,
163                                         false);
164                                 if (valueRequired) {
165                                         if ((bits & OnlyValueRequiredMASK) != 0) {
166                                                 codeStream.iconst_0();
167                                         } else {
168                                                 if (falseLabel != null) {
169                                                         // implicit falling through the TRUE case
170                                                         codeStream.goto_(falseLabel);
171                                                 }
172                                         }
173                                 }
174                         }
175                         codeStream.recordPositionsFrom(pc, this.sourceStart);
176                         if (mergedInitStateIndex != -1) {
177                                 codeStream.removeNotDefinitelyAssignedVariables(
178                                         currentScope,
179                                         mergedInitStateIndex);
180                         }
181                         return;
182                 }
183                 if ((condConst = right.conditionalConstant()) != NotAConstant) {
184                         if (condConst.booleanValue() == true) {
185                                 // x && <something equivalent to true>
186                                 if ((bits & OnlyValueRequiredMASK) != 0) {
187                                         left.generateCode(currentScope, codeStream, valueRequired);
188                                 } else {
189                                         left.generateOptimizedBoolean(
190                                                 currentScope,
191                                                 codeStream,
192                                                 trueLabel,
193                                                 falseLabel,
194                                                 valueRequired);
195                                 }
196                                 if (rightInitStateIndex != -1) {
197                                         codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
198                                 }
199                                 right.generateOptimizedBoolean(
200                                         currentScope,
201                                         codeStream,
202                                         trueLabel,
203                                         falseLabel,
204                                         false);
205                         } else {
206                                 // x && <something equivalent to false>
207                                 left.generateOptimizedBoolean(
208                                         currentScope,
209                                         codeStream,
210                                         trueLabel,
211                                         falseLabel,
212                                         false);
213                                 if (rightInitStateIndex != -1) {
214                                         codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
215                                 }
216                                 right.generateOptimizedBoolean(
217                                         currentScope,
218                                         codeStream,
219                                         trueLabel,
220                                         falseLabel,
221                                         false);
222                                 if (valueRequired) {
223                                         if ((bits & OnlyValueRequiredMASK) != 0) {
224                                                 codeStream.iconst_0();
225                                         } else {
226                                                 if (falseLabel != null) {
227                                                         // implicit falling through the TRUE case
228                                                         codeStream.goto_(falseLabel);
229                                                 }
230                                         }
231                                 }
232                         }
233                         codeStream.recordPositionsFrom(pc, this.sourceStart);
234                         if (mergedInitStateIndex != -1) {
235                                 codeStream.removeNotDefinitelyAssignedVariables(
236                                         currentScope,
237                                         mergedInitStateIndex);
238                         }
239                         return;
240                 }
241                 // default case
242                 if (falseLabel == null) {
243                         if (trueLabel != null) {
244                                 // implicit falling through the FALSE case
245                                 Label internalFalseLabel = new Label(codeStream);
246                                 left.generateOptimizedBoolean(
247                                         currentScope,
248                                         codeStream,
249                                         null,
250                                         internalFalseLabel,
251                                         true);
252                                 if (rightInitStateIndex != -1) {
253                                         codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
254                                 }
255                                 right.generateOptimizedBoolean(
256                                         currentScope,
257                                         codeStream,
258                                         trueLabel,
259                                         null,
260                                         valueRequired);
261                                 internalFalseLabel.place();
262                         }
263                 } else {
264                         // implicit falling through the TRUE case
265                         if (trueLabel == null) {
266                                 left.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, true);
267                                 if (rightInitStateIndex != -1) {
268                                         codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
269                                 }
270                                 right.generateOptimizedBoolean(
271                                         currentScope,
272                                         codeStream,
273                                         null,
274                                         falseLabel,
275                                         valueRequired);
276                         } else {
277                                 // no implicit fall through TRUE/FALSE --> should never occur
278                         }
279                 }
280                 codeStream.recordPositionsFrom(pc, this.sourceStart);
281                 if (mergedInitStateIndex != -1) {
282                         codeStream.removeNotDefinitelyAssignedVariables(
283                                 currentScope,
284                                 mergedInitStateIndex);
285                 }
286         }
287
288         public boolean isCompactableOperation() {
289                 return false;
290         }
291
292         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
293                 if (visitor.visit(this, scope)) {
294                         left.traverse(visitor, scope);
295                         right.traverse(visitor, scope);
296                 }
297                 visitor.endVisit(this, scope);
298         }
299 }