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