/*******************************************************************************
* Copyright (c) 2008, 2011 Wind River Systems, Inc. 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:
* Markus Schorn - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IEnumerator;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator;
import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator.EvalException;
import org.eclipse.cdt.internal.core.pdom.db.TypeMarshalBuffer;
import org.eclipse.core.runtime.CoreException;
/**
* Represents values of variables, enumerators or expressions. The primary purpose of the representation
* is to support instantiation of templates with non-type template parameters.
*/
public class Value implements IValue {
public static final int MAX_RECURSION_DEPTH = 25;
public final static IValue UNKNOWN= new Value("<unknown>".toCharArray(), ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY); //$NON-NLS-1$
public final static IValue NOT_INITIALIZED= new Value("<__>".toCharArray(), ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY); //$NON-NLS-1$
private static final int[] NO_INT = {};
private static final String SCOPE_OP = "::"; //$NON-NLS-1$
private static final char UNIQUE_CHAR = '_';
private static final char TEMPLATE_PARAM_CHAR = '#';
private static final char TEMPLATE_PARAM_PACK_CHAR = '`';
private static final char REFERENCE_CHAR = '&';
private static final char UNARY_OP_CHAR = '$';
private static final char BINARY_OP_CHAR = '@';
private static final char CONDITIONAL_CHAR= '?';
private static final char SEPARATOR = ',';
private final static IValue[] TYPICAL= {
new Value(new char[] {'0'}, ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY),
new Value(new char[] {'1'}, ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY),
new Value(new char[] {'2'}, ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY),
new Value(new char[] {'3'}, ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY),
new Value(new char[] {'4'}, ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY),
new Value(new char[] {'5'}, ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY),
new Value(new char[] {'6'}, ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY)};
private static class Reevaluation {
public final char[] fExpression;
private int fPackOffset;
public int pos=0;
public final Map<String, Integer> fUnknownSigs;
public final List<ICPPUnknownBinding> fUnknowns;
public final IBinding[] fResolvedUnknown;
public final ICPPTemplateParameterMap fMap;
public Reevaluation(char[] expr, int packOffset, Map<String, Integer> unknownSigs,
List<ICPPUnknownBinding> unknowns, IBinding[] resolvedUnknowns, ICPPTemplateParameterMap map) {
fExpression= expr;
fPackOffset= packOffset;
fUnknownSigs= unknownSigs;
fUnknowns= unknowns;
fResolvedUnknown= resolvedUnknowns;
fMap= map;
}
public void nextSeperator() throws UnknownValueException {
final char[] expression = fExpression;
final int len = expression.length;
int idx = pos;
while(idx < len) {
if (expression[idx++] == SEPARATOR)
break;
}
pos= idx;
}
}
private static class UnknownValueException extends Exception {}
private static UnknownValueException UNKNOWN_EX= new UnknownValueException();
private static int sUnique=0;
private final char[] fExpression;
private final ICPPUnknownBinding[] fUnknownBindings;
private char[] fSignature;
private Value(char[] rep, ICPPUnknownBinding[] unknown) {
assert rep != null;
fExpression= rep;
fUnknownBindings= unknown;
}
public char[] getInternalExpression() {
return fExpression;
}
public IBinding[] getUnknownBindings() {
return fUnknownBindings;
}
public char[] getSignature() {
if (fSignature == null) {
if (fUnknownBindings.length == 0) {
fSignature= fExpression;
} else {
StringBuilder buf= new StringBuilder();
buf.append(fExpression);
buf.append('[');
for (int i = 0; i < fUnknownBindings.length; i++) {
if (i > 0)
buf.append(',');
buf.append(getSignatureForUnknown(fUnknownBindings[i]));
}
buf.append(']');
final int end= buf.length();
fSignature= new char[end];
buf.getChars(0, end, fSignature, 0);
}
}
return fSignature;
}
public Long numericalValue() {
return parseLong(fExpression);
}
public void marshall(TypeMarshalBuffer buf) throws CoreException {
if (UNKNOWN == this) {
buf.putByte((byte) (ITypeMarshalBuffer.VALUE | ITypeMarshalBuffer.FLAG1));
} else {
Long num= numericalValue();
if (num != null) {
long lv= num;
if (lv >= Integer.MIN_VALUE && lv <= Integer.MAX_VALUE) {
buf.putByte((byte) (ITypeMarshalBuffer.VALUE | ITypeMarshalBuffer.FLAG2));
buf.putInt((int) lv);
} else {
buf.putByte((byte) (ITypeMarshalBuffer.VALUE | ITypeMarshalBuffer.FLAG3));
buf.putLong(lv);
}
} else {
buf.putByte((ITypeMarshalBuffer.VALUE));
buf.putCharArray(fExpression);
buf.putShort((short) fUnknownBindings.length);
for (ICPPUnknownBinding b : fUnknownBindings) {
buf.marshalBinding(b);
}
}
}
}
public static IValue unmarshal(TypeMarshalBuffer buf) throws CoreException {
int firstByte= buf.getByte();
if (firstByte == TypeMarshalBuffer.NULL_TYPE)
return null;
if ((firstByte & ITypeMarshalBuffer.FLAG1) != 0)
return Value.UNKNOWN;
if ((firstByte & ITypeMarshalBuffer.FLAG2) != 0) {
int val= buf.getInt();
return Value.create(val);
}
if ((firstByte & ITypeMarshalBuffer.FLAG3) != 0) {
long val= buf.getLong();
return Value.create(val);
}
char[] expr = buf.getCharArray();
final int len= buf.getShort();
ICPPUnknownBinding[] unknowns= new ICPPUnknownBinding[len];
for (int i = 0; i < unknowns.length; i++) {
final ICPPUnknownBinding unknown = (ICPPUnknownBinding) buf.unmarshalBinding();
if (unknown == null) {
return Value.UNKNOWN;
}
unknowns[i]= unknown;
}
return new Value(expr, unknowns);
}
@Override
public int hashCode() {
return CharArrayUtils.hash(fExpression);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof IValue)) {
return false;
}
final IValue rhs = (IValue) obj;
if (!CharArrayUtils.equals(fExpression, rhs.getInternalExpression()))
return false;
IBinding[] rhsUnknowns= rhs.getUnknownBindings();
if (fUnknownBindings.length != rhsUnknowns.length)
return false;
for (int i = 0; i < rhsUnknowns.length; i++) {
final IBinding rhsUnknown = rhsUnknowns[i];
if (rhsUnknown instanceof ICPPUnknownBinding) {
if (!getSignatureForUnknown((ICPPUnknownBinding) rhsUnknown).equals(getSignatureForUnknown(fUnknownBindings[i]))) {
return false;
}
} else {
return false;
}
}
return true;
}
@Override
public String toString() {
return new String(getSignature());
}
/**
* Creates a value representing the given number.
*/
public static IValue create(long value) {
if (value >=0 && value < TYPICAL.length)
return TYPICAL[(int) value];
return new Value(toCharArray(value), ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY);
}
/**
* Creates a value representing the given template parameter.
*/
public static IValue create(ICPPTemplateNonTypeParameter tntp) {
final String expr = createTemplateParamExpression(tntp.getParameterID(), tntp.isParameterPack());
return new Value(expr.toCharArray(), ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY);
}
private static String createTemplateParamExpression(int id, boolean isPack) {
StringBuilder buf= new StringBuilder();
buf.append(isPack ? TEMPLATE_PARAM_PACK_CHAR : TEMPLATE_PARAM_CHAR);
buf.append(Integer.toHexString(id));
return buf.toString();
}
/**
* Tests whether the value is a template parameter (or parameter pack),
* returns the parameter id of the parameter, or <code>-1</code> if it is not a template parameter.
*/
public static int isTemplateParameter(IValue tval) {
final char[] rep= tval.getInternalExpression();
if (rep.length > 0) {
final char c = rep[0];
if (c == TEMPLATE_PARAM_CHAR || c == TEMPLATE_PARAM_PACK_CHAR) {
for (int i = 1; i < rep.length; i++) {
if (rep[i] == SEPARATOR)
return -1;
}
try {
return parseHex(rep, 1);
} catch (UnknownValueException e) {
}
}
}
return -1;
}
/**
* Tests whether the value directly references some template parameter.
*/
public static boolean referencesTemplateParameter(IValue tval) {
final char[] rep= tval.getInternalExpression();
for (char element : rep) {
if (element == TEMPLATE_PARAM_CHAR || element == TEMPLATE_PARAM_PACK_CHAR)
return true;
}
return false;
}
/**
* Tests whether the value depends on a template parameter.
*/
public static boolean isDependentValue(IValue nonTypeValue) {
final char[] rep= nonTypeValue.getInternalExpression();
for (final char c : rep) {
if (c == REFERENCE_CHAR || c == TEMPLATE_PARAM_CHAR || c == TEMPLATE_PARAM_PACK_CHAR)
return true;
}
return false;
}
/**
* Collects all references to parameter packs.
*/
public static int[] getParameterPackReferences(IValue value) {
final char[] rep= value.getInternalExpression();
int result= -1;
List<Integer> array= null;
for (int i=0; i<rep.length-1; i++) {
if (rep[i] == TEMPLATE_PARAM_PACK_CHAR) {
int ref;
try {
ref = parseHex(rep, i + 1);
if (result < 0) {
result = ref;
} else {
if (array == null) {
array = new ArrayList<Integer>(2);
array.add(result);
}
array.add(ref);
}
} catch (UnknownValueException e) {
}
}
}
if (array != null) {
int[] ra= new int[array.size()];
for (int i = 0; i < ra.length; i++) {
ra[i]= array.get(i);
}
return ra;
}
if (result != -1)
return new int[] {result};
return NO_INT;
}
/**
* Creates the value for an expression.
*/
public static IValue create(IASTExpression expr, int maxRecursionDepth) {
try {
Map<String, Integer> unknownSigs= new HashMap<String, Integer>();
List<ICPPUnknownBinding> unknown= new ArrayList<ICPPUnknownBinding>();
Object obj= evaluate(expr, unknownSigs, unknown, maxRecursionDepth);
if (obj instanceof Number)
return create(((Number) obj).longValue());
ICPPUnknownBinding[] ua;
if (unknown.isEmpty()) {
ua= ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY;
} else {
ua= unknown.toArray(new ICPPUnknownBinding[unknown.size()]);
}
return new Value(((String)obj).toCharArray(), ua);
} catch (UnknownValueException e) {
}
return UNKNOWN;
}
/**
* Creates a value off its canonical representation.
*/
public static IValue fromInternalRepresentation(char[] rep, ICPPUnknownBinding[] unknown) {
if (CharArrayUtils.equals(rep, UNKNOWN.getInternalExpression()))
return UNKNOWN;
Long l= parseLong(rep);
if (l != null)
return create(l.longValue());
return new Value(rep, unknown);
}
/**
* Creates a unique value needed during template instantiation.
*/
public static IValue unique() {
StringBuilder buf= new StringBuilder(10);
buf.append(UNIQUE_CHAR);
buf.append(++sUnique);
return new Value(extractChars(buf), ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY);
}
/**
* Computes the canonical representation of the value of the expression.
* Returns a {@code Number} for numerical values or a {@code String}, otherwise.
* @throws UnknownValueException
*/
private static Object evaluate(IASTExpression e, Map<String, Integer> unknownSigs, List<ICPPUnknownBinding> unknowns, int maxdepth) throws UnknownValueException {
if (maxdepth < 0 || e == null)
throw UNKNOWN_EX;
if (e instanceof IASTArraySubscriptExpression) {
throw UNKNOWN_EX;
}
if (e instanceof IASTBinaryExpression) {
return evaluateBinaryExpression((IASTBinaryExpression) e, unknownSigs, unknowns, maxdepth);
}
if (e instanceof IASTCastExpression) { // must be ahead of unary
return evaluate(((IASTCastExpression) e).getOperand(), unknownSigs, unknowns, maxdepth);
}
if (e instanceof IASTUnaryExpression) {
return evaluateUnaryExpression((IASTUnaryExpression) e, unknownSigs, unknowns, maxdepth);
}
if (e instanceof IASTConditionalExpression) {
IASTConditionalExpression cexpr= (IASTConditionalExpression) e;
Object o= evaluate(cexpr.getLogicalConditionExpression(), unknownSigs, unknowns, maxdepth);
if (o instanceof Number) {
Number v= (Number) o;
if (v.longValue() == 0) {
return evaluate(cexpr.getNegativeResultExpression(), unknownSigs, unknowns, maxdepth);
}
final IASTExpression pe = cexpr.getPositiveResultExpression();
if (pe == null) // gnu-extension allows to omit the positive expression.
return o;
return evaluate(pe, unknownSigs, unknowns, maxdepth);
}
final IASTExpression pe = cexpr.getPositiveResultExpression();
Object po= pe == null ? o : evaluate(pe, unknownSigs, unknowns, maxdepth);
Object neg= evaluate(cexpr.getNegativeResultExpression(), unknownSigs, unknowns, maxdepth);
return "" + CONDITIONAL_CHAR + SEPARATOR + o.toString() + SEPARATOR + po.toString() + SEPARATOR + neg.toString(); //$NON-NLS-1$
}
if (e instanceof IASTIdExpression) {
IBinding b= ((IASTIdExpression) e).getName().resolvePreBinding();
return evaluateBinding(b, unknownSigs, unknowns, maxdepth);
}
if (e instanceof IASTLiteralExpression) {
IASTLiteralExpression litEx= (IASTLiteralExpression) e;
switch (litEx.getKind()) {
case IASTLiteralExpression.lk_false:
return 0;
case IASTLiteralExpression.lk_true:
return 1;
case IASTLiteralExpression.lk_integer_constant:
try {
return ExpressionEvaluator.getNumber(litEx.getValue());
} catch (EvalException e1) {
throw UNKNOWN_EX;
}
case IASTLiteralExpression.lk_char_constant:
try {
final char[] image= litEx.getValue();
if (image.length > 1 && image[0] == 'L')
return ExpressionEvaluator.getChar(image, 2);
return ExpressionEvaluator.getChar(image, 1);
} catch (EvalException e1) {
throw UNKNOWN_EX;
}
}
}
if (e instanceof IASTTypeIdExpression) {
IASTTypeIdExpression typeIdEx = (IASTTypeIdExpression) e;
switch (typeIdEx.getOperator()) {
case IASTTypeIdExpression.op_sizeof:
IType type = CPPVisitor.createType(typeIdEx.getTypeId());
ASTTranslationUnit ast = (ASTTranslationUnit) typeIdEx.getTranslationUnit();
SizeofCalculator calculator = ast.getSizeofCalculator();
SizeAndAlignment info = calculator.sizeAndAlignment(type);
if (info == null)
throw UNKNOWN_EX;
return info.size;
}
}
throw UNKNOWN_EX;
}
/**
* Extract a value off a binding.
*/
private static Object evaluateBinding(IBinding b, Map<String, Integer> unknownSigs, List<ICPPUnknownBinding> unknowns, int maxdepth) throws UnknownValueException {
if (b instanceof IType) {
throw UNKNOWN_EX;
}
if (b instanceof ICPPTemplateNonTypeParameter) {
final ICPPTemplateNonTypeParameter tp = (ICPPTemplateNonTypeParameter) b;
return createTemplateParamExpression(tp.getParameterID(), tp.isParameterPack());
}
if (b instanceof ICPPUnknownBinding) {
return createReference((ICPPUnknownBinding) b, unknownSigs, unknowns);
}
IValue value= null;
if (b instanceof IInternalVariable) {
value= ((IInternalVariable) b).getInitialValue(maxdepth - 1);
} else if (b instanceof IVariable) {
value= ((IVariable) b).getInitialValue();
} else if (b instanceof IEnumerator) {
value= ((IEnumerator) b).getValue();
}
if (value != null)
return evaluateValue(value, unknownSigs, unknowns);
throw UNKNOWN_EX;
}
private static Object createReference(ICPPUnknownBinding unknown, Map<String, Integer> unknownSigs, List<ICPPUnknownBinding> unknowns) {
String sig= getSignatureForUnknown(unknown);
Integer idx= unknownSigs.get(sig);
if (idx == null) {
idx= unknownSigs.size();
unknownSigs.put(sig, idx);
unknowns.add(unknown);
}
return "" + REFERENCE_CHAR + idx.toString(); //$NON-NLS-1$
}
private static Object evaluateValue(IValue cv, Map<String, Integer> unknownSigs, List<ICPPUnknownBinding> unknowns) throws UnknownValueException {
if (cv == Value.UNKNOWN)
throw UNKNOWN_EX;
Long lv= cv.numericalValue();
if (lv != null)
return lv;
final IBinding[] oldUnknowns = cv.getUnknownBindings();
final char[] expr= cv.getInternalExpression();
if (oldUnknowns.length == 0)
return new String(expr);
StringBuilder buf= new StringBuilder(expr.length);
boolean skipToSeparator= false;
for (int i = 0; i < expr.length; i++) {
final char c= expr[i];
switch (c) {
case REFERENCE_CHAR: {
int idx= parseNonNegative(expr, i + 1);
if (idx >= oldUnknowns.length)
throw UNKNOWN_EX;
final IBinding old = oldUnknowns[idx];
if (!(old instanceof ICPPUnknownBinding))
throw UNKNOWN_EX;
buf.append(createReference((ICPPUnknownBinding) old, unknownSigs, unknowns));
skipToSeparator= true;
break;
}
case SEPARATOR:
skipToSeparator= false;
buf.append(c);
break;
default:
if (!skipToSeparator)
buf.append(c);
break;
}
}
return buf.toString();
}
private static Object evaluateUnaryExpression(IASTUnaryExpression ue, Map<String, Integer> unknownSigs, List<ICPPUnknownBinding> unknowns, int maxdepth) throws UnknownValueException {
final int unaryOp= ue.getOperator();
if (unaryOp == IASTUnaryExpression.op_sizeof) {
IType type = ue.getExpressionType();
ASTTranslationUnit ast = (ASTTranslationUnit) ue.getTranslationUnit();
SizeofCalculator calculator = ast.getSizeofCalculator();
SizeAndAlignment info = calculator.sizeAndAlignment(type);
if (info == null)
throw UNKNOWN_EX;
return info.size;
}
if (unaryOp == IASTUnaryExpression.op_amper || unaryOp == IASTUnaryExpression.op_star ||
unaryOp == IASTUnaryExpression.op_sizeofParameterPack) {
throw UNKNOWN_EX;
}
final Object value= evaluate(ue.getOperand(), unknownSigs, unknowns, maxdepth);
return combineUnary(unaryOp, value);
}
private static Object combineUnary(final int unaryOp, final Object value) throws UnknownValueException {
switch (unaryOp) {
case IASTUnaryExpression.op_bracketedPrimary:
case IASTUnaryExpression.op_plus:
return value;
}
if (value instanceof Number) {
long v= ((Number) value).longValue();
switch (unaryOp) {
case IASTUnaryExpression.op_prefixIncr:
case IASTUnaryExpression.op_postFixIncr:
return ++v;
case IASTUnaryExpression.op_prefixDecr:
case IASTUnaryExpression.op_postFixDecr:
return --v;
case IASTUnaryExpression.op_minus:
return -v;
case IASTUnaryExpression.op_tilde:
return ~v;
case IASTUnaryExpression.op_not:
return v == 0 ? 1 : 0;
}
throw UNKNOWN_EX;
}
switch (unaryOp) {
case IASTUnaryExpression.op_prefixIncr:
case IASTUnaryExpression.op_postFixIncr:
case IASTUnaryExpression.op_prefixDecr:
case IASTUnaryExpression.op_postFixDecr:
case IASTUnaryExpression.op_minus:
case IASTUnaryExpression.op_tilde:
case IASTUnaryExpression.op_not:
return "" + UNARY_OP_CHAR + unaryOp + SEPARATOR + value.toString(); //$NON-NLS-1$
}
throw UNKNOWN_EX;
}
private static Object evaluateBinaryExpression(IASTBinaryExpression be,
Map<String, Integer> unknownSigs, List<ICPPUnknownBinding> unknowns, int maxdepth) throws UnknownValueException {
final Object o1= evaluate(be.getOperand1(), unknownSigs, unknowns, maxdepth);
final Object o2= evaluate(be.getOperand2(), unknownSigs, unknowns, maxdepth);
final int op= be.getOperator();
return combineBinary(op, o1, o2);
}
private static Object combineBinary(final int op, final Object o1, final Object o2) throws UnknownValueException {
if (o1 instanceof Number && o2 instanceof Number) {
long v1= ((Number) o1).longValue();
long v2= ((Number) o2).longValue();
switch (op) {
case IASTBinaryExpression.op_multiply:
return v1 * v2;
case IASTBinaryExpression.op_divide:
if (v2 == 0)
throw UNKNOWN_EX;
return v1 / v2;
case IASTBinaryExpression.op_modulo:
if (v2 == 0)
throw UNKNOWN_EX;
return v1 % v2;
case IASTBinaryExpression.op_plus:
return v1 + v2;
case IASTBinaryExpression.op_minus:
return v1 - v2;
case IASTBinaryExpression.op_shiftLeft:
return v1 << v2;
case IASTBinaryExpression.op_shiftRight:
return v1 >> v2;
case IASTBinaryExpression.op_lessThan:
return v1 < v2 ? 1 : 0;
case IASTBinaryExpression.op_greaterThan:
return v1 > v2 ? 1 : 0;
case IASTBinaryExpression.op_lessEqual:
return v1 <= v2 ? 1 : 0;
case IASTBinaryExpression.op_greaterEqual:
return v1 >= v2 ? 1 : 0;
case IASTBinaryExpression.op_binaryAnd:
return v1 & v2;
case IASTBinaryExpression.op_binaryXor:
return v1 ^ v2;
case IASTBinaryExpression.op_binaryOr:
return v1 | v2;
case IASTBinaryExpression.op_logicalAnd:
return v1 != 0 && v2 != 0 ? 1 : 0;
case IASTBinaryExpression.op_logicalOr:
return v1 != 0 || v2 != 0 ? 1 : 0;
case IASTBinaryExpression.op_equals:
return v1 == v2 ? 1 : 0;
case IASTBinaryExpression.op_notequals:
return v1 != v2 ? 1 : 0;
case IASTBinaryExpression.op_max:
return Math.max(v1, v2);
case IASTBinaryExpression.op_min:
return Math.min(v1, v2);
}
throw UNKNOWN_EX;
}
switch (op) {
case IASTBinaryExpression.op_multiply:
case IASTBinaryExpression.op_divide:
case IASTBinaryExpression.op_modulo:
case IASTBinaryExpression.op_plus:
case IASTBinaryExpression.op_minus:
case IASTBinaryExpression.op_shiftLeft:
case IASTBinaryExpression.op_shiftRight:
case IASTBinaryExpression.op_lessThan:
case IASTBinaryExpression.op_greaterThan:
case IASTBinaryExpression.op_lessEqual:
case IASTBinaryExpression.op_greaterEqual:
case IASTBinaryExpression.op_binaryAnd:
case IASTBinaryExpression.op_binaryXor:
case IASTBinaryExpression.op_binaryOr:
case IASTBinaryExpression.op_logicalAnd:
case IASTBinaryExpression.op_logicalOr:
case IASTBinaryExpression.op_max:
case IASTBinaryExpression.op_min:
break;
case IASTBinaryExpression.op_equals:
if (o1.equals(o2))
return 1;
break;
case IASTBinaryExpression.op_notequals:
if (o1.equals(o2))
return 0;
break;
default:
throw UNKNOWN_EX;
}
return "" + BINARY_OP_CHAR + op + SEPARATOR + o1.toString() + SEPARATOR + o2.toString(); //$NON-NLS-1$
}
public static IValue reevaluate(IValue val, int packOffset, IBinding[] resolvedUnknowns, ICPPTemplateParameterMap map, int maxdepth) {
try {
Map<String, Integer> unknownSigs= new HashMap<String, Integer>();
List<ICPPUnknownBinding> unknown= new ArrayList<ICPPUnknownBinding>();
Reevaluation reeval= new Reevaluation(val.getInternalExpression(), packOffset,
unknownSigs, unknown,
resolvedUnknowns, map);
Object obj= reevaluate(reeval, maxdepth);
if (reeval.pos != reeval.fExpression.length)
return UNKNOWN;
if (obj instanceof Number)
return create(((Number) obj).longValue());
ICPPUnknownBinding[] ua;
if (unknown.isEmpty()) {
ua= ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY;
} else {
ua= unknown.toArray(new ICPPUnknownBinding[unknown.size()]);
}
return new Value(((String)obj).toCharArray(), ua);
} catch (UnknownValueException e) {
}
return UNKNOWN;
}
private static Object reevaluate(Reevaluation reeval, int maxdepth)
throws UnknownValueException {
if (maxdepth < 0)
throw UNKNOWN_EX;
final int idx= reeval.pos;
final char[] buf= reeval.fExpression;
final int length = buf.length;
if (idx >= length)
throw UNKNOWN_EX;
final char c= buf[idx];
switch (c) {
case BINARY_OP_CHAR:
int op= parseNonNegative(buf, idx + 1);
reeval.nextSeperator();
Object o1= reevaluate(reeval, maxdepth);
Object o2= reevaluate(reeval, maxdepth);
return combineBinary(op, o1, o2);
case UNARY_OP_CHAR:
op= parseNonNegative(buf, idx + 1);
reeval.nextSeperator();
o1= reevaluate(reeval, maxdepth);
return combineUnary(op, o1);
case CONDITIONAL_CHAR:
reeval.nextSeperator();
Object cond= reevaluate(reeval, maxdepth);
Object po= reevaluate(reeval, maxdepth);
Object neg= reevaluate(reeval, maxdepth);
if (cond instanceof Number) {
Number v= (Number) cond;
if (v.longValue() == 0) {
return neg;
}
return po;
}
return "" + CONDITIONAL_CHAR + SEPARATOR + cond.toString() + SEPARATOR + po.toString() + SEPARATOR + neg.toString(); //$NON-NLS-1$
case REFERENCE_CHAR:
int num= parseNonNegative(buf, idx + 1);
final IBinding[] resolvedUnknowns= reeval.fResolvedUnknown;
if (num >= resolvedUnknowns.length)
throw UNKNOWN_EX;
reeval.nextSeperator();
return evaluateBinding(resolvedUnknowns[num], reeval.fUnknownSigs, reeval.fUnknowns, maxdepth);
case TEMPLATE_PARAM_CHAR:
num= parseHex(buf, idx + 1);
reeval.nextSeperator();
ICPPTemplateArgument arg = reeval.fMap.getArgument(num);
if (arg != null) {
IValue val= arg.getNonTypeValue();
if (val == null)
throw UNKNOWN_EX;
return evaluateValue(val, reeval.fUnknownSigs, reeval.fUnknowns);
}
return createTemplateParamExpression(num, false);
case TEMPLATE_PARAM_PACK_CHAR:
num= parseHex(buf, idx + 1);
reeval.nextSeperator();
arg= null;
if (reeval.fPackOffset >= 0) {
ICPPTemplateArgument[] args= reeval.fMap.getPackExpansion(num);
if (args != null && reeval.fPackOffset < args.length) {
arg= args[reeval.fPackOffset];
}
}
if (arg != null) {
IValue val= arg.getNonTypeValue();
if (val == null)
throw UNKNOWN_EX;
return evaluateValue(val, reeval.fUnknownSigs, reeval.fUnknowns);
}
return createTemplateParamExpression(num, true);
default:
reeval.nextSeperator();
return parseLong(buf, idx);
}
}
/**
* Parses a non negative int.
*/
private static int parseNonNegative(char[] value, int offset) throws UnknownValueException {
final long maxvalue= Integer.MAX_VALUE/10;
final int len= value.length;
int result = 0;
boolean ok= false;
for(; offset < len; offset++) {
final int digit= (value[offset] - '0');
if (digit < 0 || digit > 9)
break;
if (result > maxvalue)
return -1;
result= result * 10 + digit;
ok= true;
}
if (!ok)
throw UNKNOWN_EX;
return result;
}
/**
* Parses a a hex value.
*/
private static int parseHex(char[] value, int offset) throws UnknownValueException {
int result = 0;
boolean ok= false;
final int len= value.length;
for(; offset < len; offset++) {
int digit= (value[offset] - '0');
if (digit < 0 || digit > 9) {
digit += '0' - 'a' + 10;
if (digit < 10 || digit > 15) {
digit += 'a' - 'A';
if (digit < 10 || digit > 15) {
break;
}
}
}
if ((result & 0xf0000000) != 0)
throw UNKNOWN_EX;
result= (result << 4) + digit;
ok= true;
}
if (!ok)
throw UNKNOWN_EX;
return result;
}
/**
* Parses a long.
*/
private static long parseLong(char[] value, int offset) throws UnknownValueException {
final long maxvalue= Long.MAX_VALUE/10;
final int len= value.length;
boolean negative= false;
long result = 0;
boolean ok= false;
if (offset < len && value[offset] == '-') {
negative = true;
offset++;
}
for(; offset < len; offset++) {
final int digit= (value[offset] - '0');
if (digit < 0 || digit > 9)
break;
if (result > maxvalue)
throw UNKNOWN_EX;
result= result * 10 + digit;
ok= true;
}
if (!ok)
throw UNKNOWN_EX;
return negative ? -result : result;
}
/**
* Parses a long, returns <code>null</code> if not possible
*/
private static Long parseLong(char[] value) {
final long maxvalue= Long.MAX_VALUE/10;
final int len= value.length;
boolean negative= false;
long result = 0;
int i= 0;
if (len > 0 && value[0] == '-') {
negative = true;
i++;
}
if (i == len)
return null;
for(; i < len; i++) {
if (result > maxvalue)
return null;
final int digit= (value[i] - '0');
if (digit < 0 || digit > 9)
return null;
result= result * 10 + digit;
}
return negative ? -result : result;
}
/**
* Computes a signature for an unknown binding.
*/
private static String getSignatureForUnknown(ICPPUnknownBinding binding) {
IBinding owner= binding.getOwner();
if (owner instanceof IType) {
StringBuilder buf= new StringBuilder();
ASTTypeUtil.appendType((IType) owner, true, buf);
return buf.append(SCOPE_OP).append(binding.getName()).toString();
}
return binding.getName();
}
/**
* Converts long to a char array
*/
private static char[] toCharArray(long value) {
StringBuilder buf= new StringBuilder();
buf.append(value);
return extractChars(buf);
}
private static char[] extractChars(StringBuilder buf) {
final int len = buf.length();
char[] result= new char[len];
buf.getChars(0, len, result, 0);
return result;
}
}