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.ASTVisitor;
14 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
16 import net.sourceforge.phpdt.internal.compiler.flow.UnconditionalFlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
18 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
20 public class ConditionalExpression extends OperatorExpression {
22 public Expression condition, valueIfTrue, valueIfFalse;
23 public Constant optimizedBooleanConstant;
24 public Constant optimizedIfTrueConstant;
25 public Constant optimizedIfFalseConstant;
27 private int returnTypeSlotSize = 1;
29 // for local variables table attributes
30 int trueInitStateIndex = -1;
31 int falseInitStateIndex = -1;
32 int mergedInitStateIndex = -1;
34 public ConditionalExpression(
36 Expression valueIfTrue,
37 Expression valueIfFalse) {
38 this.condition = condition;
39 this.valueIfTrue = valueIfTrue;
40 this.valueIfFalse = valueIfFalse;
41 sourceStart = condition.sourceStart;
42 sourceEnd = valueIfFalse.sourceEnd;
45 public FlowInfo analyseCode(
46 BlockScope currentScope,
47 FlowContext flowContext,
50 Constant cst = this.condition.optimizedBooleanConstant();
51 boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true;
52 boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false;
54 int mode = flowInfo.reachMode();
55 flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo, cst == NotAConstant);
57 // process the if-true part
58 FlowInfo trueFlowInfo = flowInfo.initsWhenTrue().copy();
59 if (isConditionOptimizedFalse) {
60 trueFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
62 trueInitStateIndex = currentScope.methodScope().recordInitializationStates(trueFlowInfo);
63 trueFlowInfo = valueIfTrue.analyseCode(currentScope, flowContext, trueFlowInfo);
65 // process the if-false part
66 FlowInfo falseFlowInfo = flowInfo.initsWhenFalse().copy();
67 if (isConditionOptimizedTrue) {
68 falseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
70 falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo);
71 falseFlowInfo = valueIfFalse.analyseCode(currentScope, flowContext, falseFlowInfo);
73 // merge if-true & if-false initializations
75 if (isConditionOptimizedTrue){
76 mergedInfo = trueFlowInfo.addPotentialInitializationsFrom(falseFlowInfo);
77 } else if (isConditionOptimizedFalse) {
78 mergedInfo = falseFlowInfo.addPotentialInitializationsFrom(trueFlowInfo);
80 // merge using a conditional info - 1GK2BLM
81 // if ((t && (v = t)) ? t : t && (v = f)) r = v; -- ok
82 cst = this.optimizedIfTrueConstant;
83 boolean isValueIfTrueOptimizedTrue = cst != null && cst != NotAConstant && cst.booleanValue() == true;
84 boolean isValueIfTrueOptimizedFalse = cst != null && cst != NotAConstant && cst.booleanValue() == false;
86 cst = this.optimizedIfFalseConstant;
87 boolean isValueIfFalseOptimizedTrue = cst != null && cst != NotAConstant && cst.booleanValue() == true;
88 boolean isValueIfFalseOptimizedFalse = cst != null && cst != NotAConstant && cst.booleanValue() == false;
90 UnconditionalFlowInfo trueInfoWhenTrue = trueFlowInfo.initsWhenTrue().copy().unconditionalInits();
91 if (isValueIfTrueOptimizedFalse) trueInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE);
93 UnconditionalFlowInfo falseInfoWhenTrue = falseFlowInfo.initsWhenTrue().copy().unconditionalInits();
94 if (isValueIfFalseOptimizedFalse) falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE);
96 UnconditionalFlowInfo trueInfoWhenFalse = trueFlowInfo.initsWhenFalse().copy().unconditionalInits();
97 if (isValueIfTrueOptimizedTrue) trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE);
99 UnconditionalFlowInfo falseInfoWhenFalse = falseFlowInfo.initsWhenFalse().copy().unconditionalInits();
100 if (isValueIfFalseOptimizedTrue) falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE);
103 FlowInfo.conditional(
104 trueInfoWhenTrue.mergedWith(falseInfoWhenTrue),
105 trueInfoWhenFalse.mergedWith(falseInfoWhenFalse));
107 mergedInitStateIndex =
108 currentScope.methodScope().recordInitializationStates(mergedInfo);
109 mergedInfo.setReachMode(mode);
114 * Code generation for the conditional operator ?:
116 * @param currentScope net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
117 * @param codeStream net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
118 * @param valueRequired boolean
120 // public void generateCode(
121 // BlockScope currentScope,
122 // CodeStream codeStream,
123 // boolean valueRequired) {
125 // int pc = codeStream.position;
126 // Label endifLabel, falseLabel;
127 // if (constant != NotAConstant) {
128 // if (valueRequired)
129 // codeStream.generateConstant(constant, implicitConversion);
130 // codeStream.recordPositionsFrom(pc, this.sourceStart);
133 // Constant cst = condition.constant;
134 // Constant condCst = condition.optimizedBooleanConstant();
135 // boolean needTruePart =
136 // !(((cst != NotAConstant) && (cst.booleanValue() == false))
137 // || ((condCst != NotAConstant) && (condCst.booleanValue() == false)));
138 // boolean needFalsePart =
139 // !(((cst != NotAConstant) && (cst.booleanValue() == true))
140 // || ((condCst != NotAConstant) && (condCst.booleanValue() == true)));
141 // endifLabel = new Label(codeStream);
143 // // Generate code for the condition
144 // boolean needConditionValue = (cst == NotAConstant) && (condCst == NotAConstant);
145 // condition.generateOptimizedBoolean(
149 // (falseLabel = new Label(codeStream)),
150 // needConditionValue);
152 // if (trueInitStateIndex != -1) {
153 // codeStream.removeNotDefinitelyAssignedVariables(
155 // trueInitStateIndex);
156 // codeStream.addDefinitelyAssignedVariables(currentScope, trueInitStateIndex);
158 // // Then code generation
159 // if (needTruePart) {
160 // valueIfTrue.generateCode(currentScope, codeStream, valueRequired);
161 // if (needFalsePart) {
162 // // Jump over the else part
163 // int position = codeStream.position;
164 // codeStream.goto_(endifLabel);
165 // codeStream.updateLastRecordedEndPC(position);
166 // // Tune codestream stack size
167 // if (valueRequired) {
168 // codeStream.decrStackSize(returnTypeSlotSize);
172 // if (needFalsePart) {
173 // falseLabel.place();
174 // if (falseInitStateIndex != -1) {
175 // codeStream.removeNotDefinitelyAssignedVariables(
177 // falseInitStateIndex);
178 // codeStream.addDefinitelyAssignedVariables(currentScope, falseInitStateIndex);
180 // valueIfFalse.generateCode(currentScope, codeStream, valueRequired);
181 // // End of if statement
182 // endifLabel.place();
184 // // May loose some local variable initializations : affecting the local variable attributes
185 // if (mergedInitStateIndex != -1) {
186 // codeStream.removeNotDefinitelyAssignedVariables(
188 // mergedInitStateIndex);
190 // // implicit conversion
191 // if (valueRequired)
192 // codeStream.generateImplicitConversion(implicitConversion);
193 // codeStream.recordPositionsFrom(pc, this.sourceStart);
197 // * Optimized boolean code generation for the conditional operator ?:
199 // public void generateOptimizedBoolean(
200 // BlockScope currentScope,
201 // CodeStream codeStream,
204 // boolean valueRequired) {
206 // if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean) // constant
207 // || (valueIfTrue.implicitConversion >> 4) != T_boolean) { // non boolean values
208 // super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
211 // Constant cst = condition.constant;
212 // Constant condCst = condition.optimizedBooleanConstant();
213 // boolean needTruePart =
214 // !(((cst != NotAConstant) && (cst.booleanValue() == false))
215 // || ((condCst != NotAConstant) && (condCst.booleanValue() == false)));
216 // boolean needFalsePart =
217 // !(((cst != NotAConstant) && (cst.booleanValue() == true))
218 // || ((condCst != NotAConstant) && (condCst.booleanValue() == true)));
220 // Label internalFalseLabel, endifLabel = new Label(codeStream);
222 // // Generate code for the condition
223 // boolean needConditionValue = (cst == NotAConstant) && (condCst == NotAConstant);
224 // condition.generateOptimizedBoolean(
228 // internalFalseLabel = new Label(codeStream),
229 // needConditionValue);
231 // if (trueInitStateIndex != -1) {
232 // codeStream.removeNotDefinitelyAssignedVariables(
234 // trueInitStateIndex);
235 // codeStream.addDefinitelyAssignedVariables(currentScope, trueInitStateIndex);
237 // // Then code generation
238 // if (needTruePart) {
239 // valueIfTrue.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
241 // if (needFalsePart) {
242 // // Jump over the else part
243 // int position = codeStream.position;
244 // codeStream.goto_(endifLabel);
245 // codeStream.updateLastRecordedEndPC(position);
246 // // No need to decrement codestream stack size
247 // // since valueIfTrue was already consumed by branch bytecode
250 // if (needFalsePart) {
251 // internalFalseLabel.place();
252 // if (falseInitStateIndex != -1) {
253 // codeStream.removeNotDefinitelyAssignedVariables(
255 // falseInitStateIndex);
256 // codeStream.addDefinitelyAssignedVariables(currentScope, falseInitStateIndex);
258 // valueIfFalse.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
260 // // End of if statement
261 // endifLabel.place();
263 // // May loose some local variable initializations : affecting the local variable attributes
264 // if (mergedInitStateIndex != -1) {
265 // codeStream.removeNotDefinitelyAssignedVariables(
267 // mergedInitStateIndex);
269 // // no implicit conversion for boolean values
270 // codeStream.updateLastRecordedEndPC(codeStream.position);
273 // public Constant optimizedBooleanConstant() {
275 // return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant;
278 // public TypeBinding resolveType(BlockScope scope) {
280 // constant = NotAConstant;
281 // TypeBinding conditionType = condition.resolveTypeExpecting(scope, BooleanBinding);
282 // TypeBinding valueIfTrueType = valueIfTrue.resolveType(scope);
283 // TypeBinding valueIfFalseType = valueIfFalse.resolveType(scope);
284 // if (conditionType == null || valueIfTrueType == null || valueIfFalseType == null)
287 // // Propagate the constant value from the valueIfTrue and valueIFFalse expression if it is possible
288 // Constant condConstant, trueConstant, falseConstant;
289 // if ((condConstant = condition.constant) != NotAConstant
290 // && (trueConstant = valueIfTrue.constant) != NotAConstant
291 // && (falseConstant = valueIfFalse.constant) != NotAConstant) {
292 // // all terms are constant expression so we can propagate the constant
293 // // from valueIFTrue or valueIfFalse to teh receiver constant
294 // constant = condConstant.booleanValue() ? trueConstant : falseConstant;
296 // if (valueIfTrueType == valueIfFalseType) { // harmed the implicit conversion
297 // valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType);
298 // valueIfFalse.implicitConversion = valueIfTrue.implicitConversion;
299 // if (valueIfTrueType == LongBinding || valueIfTrueType == DoubleBinding) {
300 // returnTypeSlotSize = 2;
303 // if (valueIfTrueType == BooleanBinding) {
304 // this.optimizedIfTrueConstant = valueIfTrue.optimizedBooleanConstant();
305 // this.optimizedIfFalseConstant = valueIfFalse.optimizedBooleanConstant();
307 // // Propagate the optimized boolean constant if possible
308 // if ((condConstant = condition.optimizedBooleanConstant()) != NotAConstant) {
310 // this.optimizedBooleanConstant = condConstant.booleanValue()
311 // ? optimizedIfTrueConstant
312 // : optimizedIfFalseConstant;
315 // return this.resolvedType = valueIfTrueType;
317 // // Determine the return type depending on argument types
319 // if (valueIfTrueType.isNumericType() && valueIfFalseType.isNumericType()) {
320 // // (Short x Byte) or (Byte x Short)"
321 // if ((valueIfTrueType == ByteBinding && valueIfFalseType == ShortBinding)
322 // || (valueIfTrueType == ShortBinding && valueIfFalseType == ByteBinding)) {
323 // valueIfTrue.implicitWidening(ShortBinding, valueIfTrueType);
324 // valueIfFalse.implicitWidening(ShortBinding, valueIfFalseType);
325 // this.resolvedType = ShortBinding;
326 // return ShortBinding;
328 // // <Byte|Short|Char> x constant(Int) ---> <Byte|Short|Char> and reciprocally
329 // if ((valueIfTrueType == ByteBinding || valueIfTrueType == ShortBinding || valueIfTrueType == CharBinding)
330 // && (valueIfFalseType == IntBinding
331 // && valueIfFalse.isConstantValueOfTypeAssignableToType(valueIfFalseType, valueIfTrueType))) {
332 // valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType);
333 // valueIfFalse.implicitWidening(valueIfTrueType, valueIfFalseType);
334 // this.resolvedType = valueIfTrueType;
335 // return valueIfTrueType;
337 // if ((valueIfFalseType == ByteBinding
338 // || valueIfFalseType == ShortBinding
339 // || valueIfFalseType == CharBinding)
340 // && (valueIfTrueType == IntBinding
341 // && valueIfTrue.isConstantValueOfTypeAssignableToType(valueIfTrueType, valueIfFalseType))) {
342 // valueIfTrue.implicitWidening(valueIfFalseType, valueIfTrueType);
343 // valueIfFalse.implicitWidening(valueIfFalseType, valueIfFalseType);
344 // this.resolvedType = valueIfFalseType;
345 // return valueIfFalseType;
347 // // Manual binary numeric promotion
349 // if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_int)
350 // && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_int)) {
351 // valueIfTrue.implicitWidening(IntBinding, valueIfTrueType);
352 // valueIfFalse.implicitWidening(IntBinding, valueIfFalseType);
353 // this.resolvedType = IntBinding;
354 // return IntBinding;
357 // if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_long)
358 // && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_long)) {
359 // valueIfTrue.implicitWidening(LongBinding, valueIfTrueType);
360 // valueIfFalse.implicitWidening(LongBinding, valueIfFalseType);
361 // returnTypeSlotSize = 2;
362 // this.resolvedType = LongBinding;
363 // return LongBinding;
366 // if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_float)
367 // && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_float)) {
368 // valueIfTrue.implicitWidening(FloatBinding, valueIfTrueType);
369 // valueIfFalse.implicitWidening(FloatBinding, valueIfFalseType);
370 // this.resolvedType = FloatBinding;
371 // return FloatBinding;
374 // valueIfTrue.implicitWidening(DoubleBinding, valueIfTrueType);
375 // valueIfFalse.implicitWidening(DoubleBinding, valueIfFalseType);
376 // returnTypeSlotSize = 2;
377 // this.resolvedType = DoubleBinding;
378 // return DoubleBinding;
380 // // Type references (null null is already tested)
381 // if ((valueIfTrueType.isBaseType() && valueIfTrueType != NullBinding)
382 // || (valueIfFalseType.isBaseType() && valueIfFalseType != NullBinding)) {
383 // scope.problemReporter().conditionalArgumentsIncompatibleTypes(
386 // valueIfFalseType);
389 // if (valueIfFalseType.isCompatibleWith(valueIfTrueType)) {
390 // valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType);
391 // valueIfFalse.implicitWidening(valueIfTrueType, valueIfFalseType);
392 // this.resolvedType = valueIfTrueType;
393 // return valueIfTrueType;
395 // if (valueIfTrueType.isCompatibleWith(valueIfFalseType)) {
396 // valueIfTrue.implicitWidening(valueIfFalseType, valueIfTrueType);
397 // valueIfFalse.implicitWidening(valueIfFalseType, valueIfFalseType);
398 // this.resolvedType = valueIfFalseType;
399 // return valueIfFalseType;
401 // scope.problemReporter().conditionalArgumentsIncompatibleTypes(
404 // valueIfFalseType);
407 public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
409 condition.printExpression(indent, output).append(" ? "); //$NON-NLS-1$
410 valueIfTrue.printExpression(0, output).append(" : "); //$NON-NLS-1$
411 return valueIfFalse.printExpression(0, output);
413 public String toStringExpressionNoParenthesis() {
414 return condition.toStringExpression() + " ? " + //$NON-NLS-1$
415 valueIfTrue.toStringExpression() + " : " + //$NON-NLS-1$
416 valueIfFalse.toStringExpression();
419 public void traverse(ASTVisitor visitor, BlockScope scope) {
420 if (visitor.visit(this, scope)) {
421 condition.traverse(visitor, scope);
422 valueIfTrue.traverse(visitor, scope);
423 valueIfFalse.traverse(visitor, scope);
425 visitor.endVisit(this, scope);