/*******************************************************************************
* Copyright (c) 2005, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* John Camelon (IBM Rational Software) - Initial API and implementation
* Yuan Zhang / Beth Tibbitts (IBM Research)
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.c;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.IPointerType;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes;
/**
* Conditional expression in C
*/
public class CASTConditionalExpression extends ASTNode implements
IASTConditionalExpression, IASTAmbiguityParent {
private IASTExpression condition;
private IASTExpression negative;
private IASTExpression positive;
public CASTConditionalExpression() {
}
public CASTConditionalExpression(IASTExpression condition,
IASTExpression positive, IASTExpression negative) {
setLogicalConditionExpression(condition);
setPositiveResultExpression(positive);
setNegativeResultExpression(negative);
}
@Override
public CASTConditionalExpression copy() {
return copy(CopyStyle.withoutLocations);
}
@Override
public CASTConditionalExpression copy(CopyStyle style) {
CASTConditionalExpression copy = new CASTConditionalExpression();
copy.setLogicalConditionExpression(condition == null ? null : condition.copy(style));
copy.setPositiveResultExpression(positive == null ? null : positive.copy(style));
copy.setNegativeResultExpression(negative == null ? null : negative.copy(style));
return copy(copy, style);
}
@Override
public IASTExpression getLogicalConditionExpression() {
return condition;
}
@Override
public void setLogicalConditionExpression(IASTExpression expression) {
assertNotFrozen();
condition = expression;
if (expression != null) {
expression.setParent(this);
expression.setPropertyInParent(LOGICAL_CONDITION);
}
}
@Override
public IASTExpression getPositiveResultExpression() {
return positive;
}
@Override
public void setPositiveResultExpression(IASTExpression expression) {
assertNotFrozen();
this.positive = expression;
if (expression != null) {
expression.setParent(this);
expression.setPropertyInParent(POSITIVE_RESULT);
}
}
@Override
public IASTExpression getNegativeResultExpression() {
return negative;
}
@Override
public void setNegativeResultExpression(IASTExpression expression) {
assertNotFrozen();
this.negative = expression;
if (expression != null) {
expression.setParent(this);
expression.setPropertyInParent(NEGATIVE_RESULT);
}
}
@Override
public boolean accept(ASTVisitor action) {
if (action.shouldVisitExpressions) {
switch (action.visit(this)) {
case ASTVisitor.PROCESS_ABORT : return false;
case ASTVisitor.PROCESS_SKIP : return true;
default : break;
}
}
if (condition != null) if (!condition.accept(action)) return false;
if (positive != null) if (!positive.accept(action)) return false;
if (negative != null) if (!negative.accept(action)) return false;
if (action.shouldVisitExpressions) {
switch (action.leave(this)) {
case ASTVisitor.PROCESS_ABORT : return false;
case ASTVisitor.PROCESS_SKIP : return true;
default : break;
}
}
return true;
}
@Override
public void replace(IASTNode child, IASTNode other) {
if (child == condition)
{
other.setPropertyInParent(child.getPropertyInParent());
other.setParent(child.getParent());
condition = (IASTExpression) other;
}
if (child == positive)
{
other.setPropertyInParent(child.getPropertyInParent());
other.setParent(child.getParent());
positive= (IASTExpression) other;
}
if (child == negative)
{
other.setPropertyInParent(child.getPropertyInParent());
other.setParent(child.getParent());
negative= (IASTExpression) other;
}
}
@Override
public IType getExpressionType() {
IASTExpression positiveExpression = getPositiveResultExpression();
if (positiveExpression == null) {
positiveExpression= getLogicalConditionExpression();
}
IASTExpression negativeExpression = getNegativeResultExpression();
IType originalPositiveType = positiveExpression.getExpressionType();
IType originalNegativeType = getNegativeResultExpression().getExpressionType();
IType positiveType = CVisitor.unwrapTypedefs(originalPositiveType);
IType negativeType = CVisitor.unwrapTypedefs(originalNegativeType);
IType resultType = computeResultType(positiveExpression, negativeExpression,
positiveType, negativeType);
if (resultType == null) {
return ProblemType.UNKNOWN_FOR_EXPRESSION;
}
return ExpressionTypes.restoreTypedefs(resultType, originalPositiveType, originalPositiveType);
}
private IType computeResultType(IASTExpression positiveExpression, IASTExpression negativeExpression,
IType positiveType, IType negativeType) {
// [6.5.15] p5: If both the second and third operands have arithmetic type, the result type
// that would be determined by the usual arithmetic conversions, were they applied to those
// two operands, is the type of the result. If both operands have void type, the result has
// void type.
if (positiveType instanceof IBasicType && negativeType instanceof IBasicType) {
if (((IBasicType) positiveType).getKind() == IBasicType.Kind.eVoid
&& ((IBasicType) negativeType).getKind() == IBasicType.Kind.eVoid) {
return CBasicType.VOID;
}
// It doesn't really matter which operator we use here, so we'll use op_plus.
return CArithmeticConversion.convertCOperandTypes(IASTBinaryExpression.op_plus,
positiveType, negativeType);
}
// If both the operands have structure or union type, the result has that type.
if (positiveType instanceof ICompositeType && negativeType instanceof ICompositeType) {
// Both operands must have the same structure or union type as per p3.
if (positiveType.isSameType(negativeType)) {
return positiveType;
}
}
// [6.5.15] p6: If both the second and third operands are pointers or one is a null pointer
// constant and the other is a pointer, the result type is a pointer to a type qualified with
// all the type qualifiers of the types referenced by both operands. Furthermore, if both
// operands are pointers to compatible types or to differently qualified versions of compatible
// types, the result type is a pointer to an appropriately qualified version of the composite
// type; if one operand is a null pointer constant, the result has the type of the other operand;
// otherwise, one operand is a pointer to void or a qualified version of void, in which case the
// result type is a pointer to an appropriately qualified version of void.
if (CVisitor.isNullPointerConstant(positiveExpression) && negativeType instanceof IPointerType) {
return negativeType;
} else if (CVisitor.isNullPointerConstant(negativeExpression) && positiveType instanceof IPointerType) {
return positiveType;
} else if (positiveType instanceof IPointerType && negativeType instanceof IPointerType) {
IType positivePointeeCV = ((IPointerType) positiveType).getType();
IType negativePointeeCV = ((IPointerType) negativeType).getType();
IType positivePointee = CVisitor.unwrapCV(positivePointeeCV);
IType negativePointee = CVisitor.unwrapCV(negativePointeeCV);
IType resultPointee;
if (positivePointee.isSameType(CBasicType.VOID) || negativePointee.isSameType(CBasicType.VOID)) {
resultPointee = CBasicType.VOID;
} else {
// TODO: Implement checking for compatible types and computing the composite type.
resultPointee = negativePointee;
}
return new CPointerType(
ExpressionTypes.restoreCV(resultPointee, positivePointeeCV, negativePointeeCV), 0);
}
return null;
}
@Override
public boolean isLValue() {
return false;
}
@Override
public final ValueCategory getValueCategory() {
return ValueCategory.PRVALUE;
}
}