1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpeclipse.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.codegen.Label;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.flow.UnconditionalFlowInfo;
18 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypeBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
21 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
23 public class ConditionalExpression extends OperatorExpression {
25 public Expression condition, valueIfTrue, valueIfFalse;
26 public Constant optimizedBooleanConstant;
27 public Constant optimizedIfTrueConstant;
28 public Constant optimizedIfFalseConstant;
30 private int returnTypeSlotSize = 1;
32 // for local variables table attributes
33 int trueInitStateIndex = -1;
34 int falseInitStateIndex = -1;
35 int mergedInitStateIndex = -1;
37 public ConditionalExpression(
39 Expression valueIfTrue,
40 Expression valueIfFalse) {
41 this.condition = condition;
42 this.valueIfTrue = valueIfTrue;
43 this.valueIfFalse = valueIfFalse;
44 sourceStart = condition.sourceStart;
45 sourceEnd = valueIfFalse.sourceEnd;
48 public FlowInfo analyseCode(
49 BlockScope currentScope,
50 FlowContext flowContext,
53 Constant cst = this.condition.optimizedBooleanConstant();
54 boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true;
55 boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false;
57 int mode = flowInfo.reachMode();
58 flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo, cst == NotAConstant);
60 // process the if-true part
61 FlowInfo trueFlowInfo = flowInfo.initsWhenTrue().copy();
62 if (isConditionOptimizedFalse) {
63 trueFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
65 trueInitStateIndex = currentScope.methodScope().recordInitializationStates(trueFlowInfo);
66 trueFlowInfo = valueIfTrue.analyseCode(currentScope, flowContext, trueFlowInfo);
68 // process the if-false part
69 FlowInfo falseFlowInfo = flowInfo.initsWhenFalse().copy();
70 if (isConditionOptimizedTrue) {
71 falseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
73 falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo);
74 falseFlowInfo = valueIfFalse.analyseCode(currentScope, flowContext, falseFlowInfo);
76 // merge if-true & if-false initializations
78 if (isConditionOptimizedTrue){
79 mergedInfo = trueFlowInfo.addPotentialInitializationsFrom(falseFlowInfo);
80 } else if (isConditionOptimizedFalse) {
81 mergedInfo = falseFlowInfo.addPotentialInitializationsFrom(trueFlowInfo);
83 // merge using a conditional info - 1GK2BLM
84 // if ((t && (v = t)) ? t : t && (v = f)) r = v; -- ok
85 cst = this.optimizedIfTrueConstant;
86 boolean isValueIfTrueOptimizedTrue = cst != null && cst != NotAConstant && cst.booleanValue() == true;
87 boolean isValueIfTrueOptimizedFalse = cst != null && cst != NotAConstant && cst.booleanValue() == false;
89 cst = this.optimizedIfFalseConstant;
90 boolean isValueIfFalseOptimizedTrue = cst != null && cst != NotAConstant && cst.booleanValue() == true;
91 boolean isValueIfFalseOptimizedFalse = cst != null && cst != NotAConstant && cst.booleanValue() == false;
93 UnconditionalFlowInfo trueInfoWhenTrue = trueFlowInfo.initsWhenTrue().copy().unconditionalInits();
94 if (isValueIfTrueOptimizedFalse) trueInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE);
96 UnconditionalFlowInfo falseInfoWhenTrue = falseFlowInfo.initsWhenTrue().copy().unconditionalInits();
97 if (isValueIfFalseOptimizedFalse) falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE);
99 UnconditionalFlowInfo trueInfoWhenFalse = trueFlowInfo.initsWhenFalse().copy().unconditionalInits();
100 if (isValueIfTrueOptimizedTrue) trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE);
102 UnconditionalFlowInfo falseInfoWhenFalse = falseFlowInfo.initsWhenFalse().copy().unconditionalInits();
103 if (isValueIfFalseOptimizedTrue) falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE);
106 FlowInfo.conditional(
107 trueInfoWhenTrue.mergedWith(falseInfoWhenTrue),
108 trueInfoWhenFalse.mergedWith(falseInfoWhenFalse));
110 mergedInitStateIndex =
111 currentScope.methodScope().recordInitializationStates(mergedInfo);
112 mergedInfo.setReachMode(mode);
117 * Code generation for the conditional operator ?:
119 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
120 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
121 * @param valueRequired boolean
123 // public void generateCode(
124 // BlockScope currentScope,
125 // CodeStream codeStream,
126 // boolean valueRequired) {
128 // int pc = codeStream.position;
129 // Label endifLabel, falseLabel;
130 // if (constant != NotAConstant) {
131 // if (valueRequired)
132 // codeStream.generateConstant(constant, implicitConversion);
133 // codeStream.recordPositionsFrom(pc, this.sourceStart);
136 // Constant cst = condition.constant;
137 // Constant condCst = condition.optimizedBooleanConstant();
138 // boolean needTruePart =
139 // !(((cst != NotAConstant) && (cst.booleanValue() == false))
140 // || ((condCst != NotAConstant) && (condCst.booleanValue() == false)));
141 // boolean needFalsePart =
142 // !(((cst != NotAConstant) && (cst.booleanValue() == true))
143 // || ((condCst != NotAConstant) && (condCst.booleanValue() == true)));
144 // endifLabel = new Label(codeStream);
146 // // Generate code for the condition
147 // boolean needConditionValue = (cst == NotAConstant) && (condCst == NotAConstant);
148 // condition.generateOptimizedBoolean(
152 // (falseLabel = new Label(codeStream)),
153 // needConditionValue);
155 // if (trueInitStateIndex != -1) {
156 // codeStream.removeNotDefinitelyAssignedVariables(
158 // trueInitStateIndex);
159 // codeStream.addDefinitelyAssignedVariables(currentScope, trueInitStateIndex);
161 // // Then code generation
162 // if (needTruePart) {
163 // valueIfTrue.generateCode(currentScope, codeStream, valueRequired);
164 // if (needFalsePart) {
165 // // Jump over the else part
166 // int position = codeStream.position;
167 // codeStream.goto_(endifLabel);
168 // codeStream.updateLastRecordedEndPC(position);
169 // // Tune codestream stack size
170 // if (valueRequired) {
171 // codeStream.decrStackSize(returnTypeSlotSize);
175 // if (needFalsePart) {
176 // falseLabel.place();
177 // if (falseInitStateIndex != -1) {
178 // codeStream.removeNotDefinitelyAssignedVariables(
180 // falseInitStateIndex);
181 // codeStream.addDefinitelyAssignedVariables(currentScope, falseInitStateIndex);
183 // valueIfFalse.generateCode(currentScope, codeStream, valueRequired);
184 // // End of if statement
185 // endifLabel.place();
187 // // May loose some local variable initializations : affecting the local variable attributes
188 // if (mergedInitStateIndex != -1) {
189 // codeStream.removeNotDefinitelyAssignedVariables(
191 // mergedInitStateIndex);
193 // // implicit conversion
194 // if (valueRequired)
195 // codeStream.generateImplicitConversion(implicitConversion);
196 // codeStream.recordPositionsFrom(pc, this.sourceStart);
200 // * Optimized boolean code generation for the conditional operator ?:
202 // public void generateOptimizedBoolean(
203 // BlockScope currentScope,
204 // CodeStream codeStream,
207 // boolean valueRequired) {
209 // if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean) // constant
210 // || (valueIfTrue.implicitConversion >> 4) != T_boolean) { // non boolean values
211 // super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
214 // Constant cst = condition.constant;
215 // Constant condCst = condition.optimizedBooleanConstant();
216 // boolean needTruePart =
217 // !(((cst != NotAConstant) && (cst.booleanValue() == false))
218 // || ((condCst != NotAConstant) && (condCst.booleanValue() == false)));
219 // boolean needFalsePart =
220 // !(((cst != NotAConstant) && (cst.booleanValue() == true))
221 // || ((condCst != NotAConstant) && (condCst.booleanValue() == true)));
223 // Label internalFalseLabel, endifLabel = new Label(codeStream);
225 // // Generate code for the condition
226 // boolean needConditionValue = (cst == NotAConstant) && (condCst == NotAConstant);
227 // condition.generateOptimizedBoolean(
231 // internalFalseLabel = new Label(codeStream),
232 // needConditionValue);
234 // if (trueInitStateIndex != -1) {
235 // codeStream.removeNotDefinitelyAssignedVariables(
237 // trueInitStateIndex);
238 // codeStream.addDefinitelyAssignedVariables(currentScope, trueInitStateIndex);
240 // // Then code generation
241 // if (needTruePart) {
242 // valueIfTrue.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
244 // if (needFalsePart) {
245 // // Jump over the else part
246 // int position = codeStream.position;
247 // codeStream.goto_(endifLabel);
248 // codeStream.updateLastRecordedEndPC(position);
249 // // No need to decrement codestream stack size
250 // // since valueIfTrue was already consumed by branch bytecode
253 // if (needFalsePart) {
254 // internalFalseLabel.place();
255 // if (falseInitStateIndex != -1) {
256 // codeStream.removeNotDefinitelyAssignedVariables(
258 // falseInitStateIndex);
259 // codeStream.addDefinitelyAssignedVariables(currentScope, falseInitStateIndex);
261 // valueIfFalse.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
263 // // End of if statement
264 // endifLabel.place();
266 // // May loose some local variable initializations : affecting the local variable attributes
267 // if (mergedInitStateIndex != -1) {
268 // codeStream.removeNotDefinitelyAssignedVariables(
270 // mergedInitStateIndex);
272 // // no implicit conversion for boolean values
273 // codeStream.updateLastRecordedEndPC(codeStream.position);
276 // public Constant optimizedBooleanConstant() {
278 // return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant;
281 // public TypeBinding resolveType(BlockScope scope) {
283 // constant = NotAConstant;
284 // TypeBinding conditionType = condition.resolveTypeExpecting(scope, BooleanBinding);
285 // TypeBinding valueIfTrueType = valueIfTrue.resolveType(scope);
286 // TypeBinding valueIfFalseType = valueIfFalse.resolveType(scope);
287 // if (conditionType == null || valueIfTrueType == null || valueIfFalseType == null)
290 // // Propagate the constant value from the valueIfTrue and valueIFFalse expression if it is possible
291 // Constant condConstant, trueConstant, falseConstant;
292 // if ((condConstant = condition.constant) != NotAConstant
293 // && (trueConstant = valueIfTrue.constant) != NotAConstant
294 // && (falseConstant = valueIfFalse.constant) != NotAConstant) {
295 // // all terms are constant expression so we can propagate the constant
296 // // from valueIFTrue or valueIfFalse to teh receiver constant
297 // constant = condConstant.booleanValue() ? trueConstant : falseConstant;
299 // if (valueIfTrueType == valueIfFalseType) { // harmed the implicit conversion
300 // valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType);
301 // valueIfFalse.implicitConversion = valueIfTrue.implicitConversion;
302 // if (valueIfTrueType == LongBinding || valueIfTrueType == DoubleBinding) {
303 // returnTypeSlotSize = 2;
306 // if (valueIfTrueType == BooleanBinding) {
307 // this.optimizedIfTrueConstant = valueIfTrue.optimizedBooleanConstant();
308 // this.optimizedIfFalseConstant = valueIfFalse.optimizedBooleanConstant();
310 // // Propagate the optimized boolean constant if possible
311 // if ((condConstant = condition.optimizedBooleanConstant()) != NotAConstant) {
313 // this.optimizedBooleanConstant = condConstant.booleanValue()
314 // ? optimizedIfTrueConstant
315 // : optimizedIfFalseConstant;
318 // return this.resolvedType = valueIfTrueType;
320 // // Determine the return type depending on argument types
322 // if (valueIfTrueType.isNumericType() && valueIfFalseType.isNumericType()) {
323 // // (Short x Byte) or (Byte x Short)"
324 // if ((valueIfTrueType == ByteBinding && valueIfFalseType == ShortBinding)
325 // || (valueIfTrueType == ShortBinding && valueIfFalseType == ByteBinding)) {
326 // valueIfTrue.implicitWidening(ShortBinding, valueIfTrueType);
327 // valueIfFalse.implicitWidening(ShortBinding, valueIfFalseType);
328 // this.resolvedType = ShortBinding;
329 // return ShortBinding;
331 // // <Byte|Short|Char> x constant(Int) ---> <Byte|Short|Char> and reciprocally
332 // if ((valueIfTrueType == ByteBinding || valueIfTrueType == ShortBinding || valueIfTrueType == CharBinding)
333 // && (valueIfFalseType == IntBinding
334 // && valueIfFalse.isConstantValueOfTypeAssignableToType(valueIfFalseType, valueIfTrueType))) {
335 // valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType);
336 // valueIfFalse.implicitWidening(valueIfTrueType, valueIfFalseType);
337 // this.resolvedType = valueIfTrueType;
338 // return valueIfTrueType;
340 // if ((valueIfFalseType == ByteBinding
341 // || valueIfFalseType == ShortBinding
342 // || valueIfFalseType == CharBinding)
343 // && (valueIfTrueType == IntBinding
344 // && valueIfTrue.isConstantValueOfTypeAssignableToType(valueIfTrueType, valueIfFalseType))) {
345 // valueIfTrue.implicitWidening(valueIfFalseType, valueIfTrueType);
346 // valueIfFalse.implicitWidening(valueIfFalseType, valueIfFalseType);
347 // this.resolvedType = valueIfFalseType;
348 // return valueIfFalseType;
350 // // Manual binary numeric promotion
352 // if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_int)
353 // && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_int)) {
354 // valueIfTrue.implicitWidening(IntBinding, valueIfTrueType);
355 // valueIfFalse.implicitWidening(IntBinding, valueIfFalseType);
356 // this.resolvedType = IntBinding;
357 // return IntBinding;
360 // if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_long)
361 // && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_long)) {
362 // valueIfTrue.implicitWidening(LongBinding, valueIfTrueType);
363 // valueIfFalse.implicitWidening(LongBinding, valueIfFalseType);
364 // returnTypeSlotSize = 2;
365 // this.resolvedType = LongBinding;
366 // return LongBinding;
369 // if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_float)
370 // && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_float)) {
371 // valueIfTrue.implicitWidening(FloatBinding, valueIfTrueType);
372 // valueIfFalse.implicitWidening(FloatBinding, valueIfFalseType);
373 // this.resolvedType = FloatBinding;
374 // return FloatBinding;
377 // valueIfTrue.implicitWidening(DoubleBinding, valueIfTrueType);
378 // valueIfFalse.implicitWidening(DoubleBinding, valueIfFalseType);
379 // returnTypeSlotSize = 2;
380 // this.resolvedType = DoubleBinding;
381 // return DoubleBinding;
383 // // Type references (null null is already tested)
384 // if ((valueIfTrueType.isBaseType() && valueIfTrueType != NullBinding)
385 // || (valueIfFalseType.isBaseType() && valueIfFalseType != NullBinding)) {
386 // scope.problemReporter().conditionalArgumentsIncompatibleTypes(
389 // valueIfFalseType);
392 // if (valueIfFalseType.isCompatibleWith(valueIfTrueType)) {
393 // valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType);
394 // valueIfFalse.implicitWidening(valueIfTrueType, valueIfFalseType);
395 // this.resolvedType = valueIfTrueType;
396 // return valueIfTrueType;
398 // if (valueIfTrueType.isCompatibleWith(valueIfFalseType)) {
399 // valueIfTrue.implicitWidening(valueIfFalseType, valueIfTrueType);
400 // valueIfFalse.implicitWidening(valueIfFalseType, valueIfFalseType);
401 // this.resolvedType = valueIfFalseType;
402 // return valueIfFalseType;
404 // scope.problemReporter().conditionalArgumentsIncompatibleTypes(
407 // valueIfFalseType);
411 public String toStringExpressionNoParenthesis() {
412 return condition.toStringExpression() + " ? " + //$NON-NLS-1$
413 valueIfTrue.toStringExpression() + " : " + //$NON-NLS-1$
414 valueIfFalse.toStringExpression();
417 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
418 if (visitor.visit(this, scope)) {
419 condition.traverse(visitor, scope);
420 valueIfTrue.traverse(visitor, scope);
421 valueIfFalse.traverse(visitor, scope);
423 visitor.endVisit(this, scope);