/*******************************************************************************
* Copyright (c) 2004, 2011 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) - Initial API and implementation
* Mike Kucera (IBM) - implicit names
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.typeFromFunctionCall;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.typeFromReturnType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.typeOrFunctionSet;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.valueCat;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.valueCategoryFromFunctionCall;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.valueCategoryFromReturnType;
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpressionList;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
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.CPPSemantics;
public class CPPASTExpressionList extends ASTNode implements ICPPASTExpressionList, IASTAmbiguityParent {
private static final ICPPFunction[] NO_FUNCTIONS = new ICPPFunction[0];
private IASTExpression[] expressions = new IASTExpression[2];
/**
* Caution: may contain nulls.
* @see CPPASTExpressionList#computeImplicitNames
*/
private IASTImplicitName[] implicitNames;
private ICPPFunction[] overloads = null;
public CPPASTExpressionList copy() {
return copy(CopyStyle.withoutLocations);
}
public CPPASTExpressionList copy(CopyStyle style) {
CPPASTExpressionList copy = new CPPASTExpressionList();
for(IASTExpression expr : getExpressions())
copy.addExpression(expr == null ? null : expr.copy(style));
copy.setOffsetAndLength(this);
if (style == CopyStyle.withLocations) {
copy.setCopyLocation(this);
}
return copy;
}
public IASTExpression[] getExpressions() {
if (expressions == null) return IASTExpression.EMPTY_EXPRESSION_ARRAY;
return (IASTExpression[]) ArrayUtil.trim(IASTExpression.class, expressions);
}
public void addExpression(IASTExpression expression) {
assertNotFrozen();
expressions = ArrayUtil.append(expressions, expression);
if (expression != null) {
expression.setParent(this);
expression.setPropertyInParent(NESTED_EXPRESSION);
}
}
@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;
}
}
IASTExpression[] exps = getExpressions();
IASTImplicitName[] implicits = action.shouldVisitImplicitNames ? computeImplicitNames() : null;
for (int i = 0, n = exps.length; i < n; i++) {
if (!exps[i].accept(action)) {
return false;
}
if (i < n - 1 && implicits != null && implicits[i] != null) {
if (!implicits[i].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;
}
/**
* Returns an array of implicit names where each element of the array
* represents a comma between the expression in the same index and the
* next expression. This array contains null elements as placeholders
* for commas that do not resolve to overloaded operators.
*/
private IASTImplicitName[] computeImplicitNames() {
if (implicitNames == null) {
IASTExpression[] exprs = getExpressions(); // has to be at least two
if (exprs.length < 2)
return implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY;
implicitNames = new IASTImplicitName[exprs.length-1];
ICPPFunction[] overloads = getOverloads();
for(int i = 0; i < overloads.length; i++) {
ICPPFunction overload = overloads[i];
if (overload != null && !(overload instanceof CPPImplicitFunction)) {
CPPASTImplicitName operatorName = new CPPASTImplicitName(OverloadableOperator.COMMA, this);
operatorName.setBinding(overload);
operatorName.computeOperatorOffsets(exprs[i], true);
implicitNames[i] = operatorName;
}
}
}
return implicitNames;
}
public IASTImplicitName[] getImplicitNames() {
return (IASTImplicitName[])ArrayUtil.removeNulls(IASTImplicitName.class, computeImplicitNames());
}
private ICPPFunction[] getOverloads() {
if (overloads == null) {
IASTExpression[] exprs = getExpressions();
if (exprs.length < 2)
return overloads = NO_FUNCTIONS;
ASTNodeProperty prop = getPropertyInParent();
if (prop == IASTFunctionCallExpression.ARGUMENT ||
prop == ICPPASTConstructorChainInitializer.INITIALIZER ||
prop == ICPPASTConstructorInitializer.ARGUMENT ||
prop == ICPPASTNewExpression.NEW_INITIALIZER)
return overloads = NO_FUNCTIONS;
overloads = new ICPPFunction[exprs.length-1];
IType lookupType = typeOrFunctionSet(exprs[0]);
ValueCategory vcat= valueCat(exprs[0]);
for (int i = 1; i < exprs.length; i++) {
IASTExpression e1 = exprs[i - 1], e2 = exprs[i];
ICPPFunction overload = CPPSemantics.findOverloadedOperatorComma(e1, lookupType, vcat, e2);
if (overload == null) {
lookupType = typeOrFunctionSet(e2);
vcat= valueCat(e2);
} else {
overloads[i - 1] = overload;
lookupType = overload.getType().getReturnType();
vcat= valueCategoryFromReturnType(lookupType);
lookupType= typeFromReturnType(lookupType);
if (lookupType instanceof ISemanticProblem) {
lookupType = typeOrFunctionSet(e2);
vcat= valueCat(e2);
}
}
}
}
return overloads;
}
public void replace(IASTNode child, IASTNode other) {
if (expressions == null) return;
for (int i = 0; i < expressions.length; ++i) {
if (child == expressions[i]) {
other.setPropertyInParent(child.getPropertyInParent());
other.setParent(child.getParent());
expressions[i] = (IASTExpression) other;
}
}
}
public IType getExpressionType() {
ICPPFunction[] overloads = getOverloads();
if (overloads.length > 0) {
ICPPFunction last = overloads[overloads.length - 1];
if (last != null) {
return typeFromFunctionCall(last);
}
}
for (int i = expressions.length - 1; i >= 0; i--) {
IASTExpression expr = expressions[i];
if (expr != null)
return expr.getExpressionType();
}
return new ProblemType(ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION);
}
public ValueCategory getValueCategory() {
ICPPFunction[] overloads = getOverloads();
if (overloads.length > 0) {
ICPPFunction last = overloads[overloads.length - 1];
if (last != null) {
return valueCategoryFromFunctionCall(last);
}
}
for (int i = expressions.length-1; i >= 0; i--) {
IASTExpression expr= expressions[i];
if (expr != null)
return expr.getValueCategory();
}
return PRVALUE;
}
public boolean isLValue() {
return getValueCategory() == LVALUE;
}
}