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