/******************************************************************************* * Copyright (c) 2008, 2012 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 static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_alignof; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_nothrow_constructor; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_nothrow_copy; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_trivial_assign; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_trivial_constructor; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_trivial_copy; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_trivial_destructor; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_virtual_destructor; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_abstract; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_class; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_empty; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_enum; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_literal_type; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_pod; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_polymorphic; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_standard_layout; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_trivial; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_union; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_sizeof; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_typeid; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_typeof; import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryTypeIdExpression; 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.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IASTNode; 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.ICompositeType; import org.eclipse.cdt.core.dom.ast.IEnumeration; 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.ICPPASTInitializerClause; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter; 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.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalBinary; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.TypeTraits; 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; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; /** * 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 static final Value UNKNOWN= new Value("".toCharArray(), null); //$NON-NLS-1$ public static final Value NOT_INITIALIZED= new Value("<__>".toCharArray(), null); //$NON-NLS-1$ private static final IType INT_TYPE= new CPPBasicType(ICPPBasicType.Kind.eInt, 0); private static final Number VALUE_CANNOT_BE_DETERMINED = new Number() { @Override public int intValue() { throw new UnsupportedOperationException(); } @Override public long longValue() { throw new UnsupportedOperationException(); } @Override public float floatValue() { throw new UnsupportedOperationException(); } @Override public double doubleValue() { throw new UnsupportedOperationException(); } }; private static final char UNIQUE_CHAR = '_'; private final static IValue[] TYPICAL= { new Value(new char[] {'0'}, null), new Value(new char[] {'1'}, null), new Value(new char[] {'2'}, null), new Value(new char[] {'3'}, null), new Value(new char[] {'4'}, null), new Value(new char[] {'5'}, null), new Value(new char[] {'6'}, null)}; private static int sUnique= 0; // The following invariant always holds: (fFixedValue == null) != (fEvaluation == null) private final char[] fFixedValue; private final ICPPEvaluation fEvaluation; private char[] fSignature; private Value(char[] fixedValue, ICPPEvaluation evaluation) { assert (fixedValue == null) != (evaluation == null); fFixedValue = fixedValue; fEvaluation = evaluation; } @Override public Long numericalValue() { return fFixedValue == null ? null : parseLong(fFixedValue); } @Override public ICPPEvaluation getEvaluation() { return fEvaluation; } @Override public char[] getSignature() { if (fSignature == null) { fSignature = fFixedValue != null ? fFixedValue : fEvaluation.getSignature(); } return fSignature; } @Deprecated @Override public char[] getInternalExpression() { return CharArrayUtils.EMPTY_CHAR_ARRAY; } @Deprecated @Override public IBinding[] getUnknownBindings() { return IBinding.EMPTY_BINDING_ARRAY; } public void marshal(ITypeMarshalBuffer buf) throws CoreException { if (UNKNOWN == this) { buf.putShort((short) (ITypeMarshalBuffer.VALUE | ITypeMarshalBuffer.FLAG1)); } else { Long num= numericalValue(); if (num != null) { long lv= num; if (lv >= 0) { buf.putShort((short) (ITypeMarshalBuffer.VALUE | ITypeMarshalBuffer.FLAG2)); buf.putLong(lv); } else { buf.putShort((short) (ITypeMarshalBuffer.VALUE | ITypeMarshalBuffer.FLAG3)); buf.putLong(-lv); } } else if (fFixedValue != null) { buf.putShort((short) (ITypeMarshalBuffer.VALUE | ITypeMarshalBuffer.FLAG4)); buf.putCharArray(fFixedValue); } else { buf.putShort(ITypeMarshalBuffer.VALUE); fEvaluation.marshal(buf, true); } } } public static IValue unmarshal(ITypeMarshalBuffer buf) throws CoreException { short firstBytes= buf.getShort(); if (firstBytes == TypeMarshalBuffer.NULL_TYPE) return null; if ((firstBytes & ITypeMarshalBuffer.FLAG1) != 0) return Value.UNKNOWN; if ((firstBytes & ITypeMarshalBuffer.FLAG2) != 0) return Value.create(buf.getLong()); if ((firstBytes & ITypeMarshalBuffer.FLAG3) != 0) return Value.create(-buf.getLong()); if ((firstBytes & ITypeMarshalBuffer.FLAG4) != 0) return new Value(buf.getCharArray(), null); ISerializableEvaluation eval= buf.unmarshalEvaluation(); if (eval instanceof ICPPEvaluation) return new Value(null, (ICPPEvaluation) eval); return Value.UNKNOWN; } @Override public int hashCode() { return CharArrayUtils.hash(getSignature()); } @Override public boolean equals(Object obj) { if (!(obj instanceof Value)) { return false; } final Value rhs = (Value) obj; if (fFixedValue != null) return CharArrayUtils.equals(fFixedValue, rhs.fFixedValue); return CharArrayUtils.equals(getSignature(), rhs.getSignature()); } @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), null); } /** * Creates a value object representing the given boolean value. */ public static IValue create(boolean value) { return create(value ? 1 : 0); } /** * Creates a value representing the given template parameter * in the given template. */ public static IValue create(ICPPTemplateDefinition template, ICPPTemplateNonTypeParameter tntp) { EvalBinding eval = new EvalBinding(tntp, null, template); return new Value(null, eval); } /** * Create a value wrapping the given evaluation. */ public static IValue create(ICPPEvaluation eval) { return new Value(null, eval); } public static IValue evaluateBinaryExpression(final int op, final long v1, final long v2) { Number val = applyBinaryOperator(op, v1, v2); if (val != null && val != VALUE_CANNOT_BE_DETERMINED) return create(val.longValue()); return UNKNOWN; } public static IValue evaluateUnaryExpression(final int unaryOp, final long value) { Number val = applyUnaryOperator(unaryOp, value); if (val != null && val != VALUE_CANNOT_BE_DETERMINED) return create(val.longValue()); return UNKNOWN; } public static IValue evaluateUnaryTypeIdExpression(int operator, IType type, IASTNode point) { Number val = applyUnaryTypeIdOperator(operator, type, point); if (val != null && val != VALUE_CANNOT_BE_DETERMINED) return create(val.longValue()); return UNKNOWN; } public static IValue evaluateBinaryTypeIdExpression(IASTBinaryTypeIdExpression.Operator operator, IType type1, IType type2, IASTNode point) { Number val = applyBinaryTypeIdOperator(operator, type1, type2, point); if (val != null && val != VALUE_CANNOT_BE_DETERMINED) return create(val.longValue()); return UNKNOWN; } public static IValue incrementedValue(IValue value, int increment) { if (value == UNKNOWN) return UNKNOWN; Long val = value.numericalValue(); if (val != null) { return create(val.longValue() + increment); } ICPPEvaluation arg1 = value.getEvaluation(); EvalFixed arg2 = new EvalFixed(INT_TYPE, ValueCategory.PRVALUE, create(increment)); return create(new EvalBinary(IASTBinaryExpression.op_plus, arg1, arg2, arg1.getTemplateDefinition())); } private static Number applyUnaryTypeIdOperator(int operator, IType type, IASTNode point) { switch (operator) { case op_sizeof: return getSize(type, point); case op_alignof: return getAlignment(type, point); case op_typeid: break; // TODO(sprigogin): Implement case op_has_nothrow_copy: break; // TODO(sprigogin): Implement case op_has_nothrow_constructor: break; // TODO(sprigogin): Implement case op_has_trivial_assign: break; // TODO(sprigogin): Implement case op_has_trivial_constructor: break; // TODO(sprigogin): Implement case op_has_trivial_copy: return !(type instanceof ICPPClassType) || TypeTraits.hasTrivialCopyCtor((ICPPClassType) type, point) ? 1 : 0; case op_has_trivial_destructor: break; // TODO(sprigogin): Implement case op_has_virtual_destructor: break; // TODO(sprigogin): Implement case op_is_abstract: return type instanceof ICPPClassType && TypeTraits.isAbstract((ICPPClassType) type, point) ? 1 : 0; case op_is_class: return type instanceof ICompositeType && ((ICompositeType) type).getKey() != ICompositeType.k_union ? 1 : 0; case op_is_empty: break; // TODO(sprigogin): Implement case op_is_enum: return type instanceof IEnumeration ? 1 : 0; case op_is_literal_type: break; // TODO(sprigogin): Implement case op_is_pod: return TypeTraits.isPOD(type, point) ? 1 : 0; case op_is_polymorphic: return type instanceof ICPPClassType && TypeTraits.isPolymorphic((ICPPClassType) type, point) ? 1 : 0; case op_is_standard_layout: return TypeTraits.isStandardLayout(type, point) ? 1 : 0; case op_is_trivial: return type instanceof ICPPClassType && TypeTraits.isTrivial((ICPPClassType) type, point) ? 1 : 0; case op_is_union: return type instanceof ICompositeType && ((ICompositeType) type).getKey() == ICompositeType.k_union ? 1 : 0; case op_typeof: break; // TODO(sprigogin): Implement } return VALUE_CANNOT_BE_DETERMINED; } public static Number applyBinaryTypeIdOperator(IASTBinaryTypeIdExpression.Operator operator, IType type1, IType type2, IASTNode point) { switch (operator) { case __is_base_of: type1 = SemanticUtil.getNestedType(type1, TDEF); type2 = SemanticUtil.getNestedType(type2, TDEF); if (type1 instanceof ICPPClassType && type2 instanceof ICPPClassType) { return ClassTypeHelper.isSubclass((ICPPClassType) type2, (ICPPClassType) type1) ? 1 : 0; } else { return 0; } } return VALUE_CANNOT_BE_DETERMINED; } private static Number getAlignment(IType type, IASTNode point) { SizeAndAlignment sizeAndAlignment = SizeofCalculator.getSizeAndAlignment(type, point); if (sizeAndAlignment == null) return VALUE_CANNOT_BE_DETERMINED; return sizeAndAlignment.alignment; } private static Number getSize(IType type, IASTNode point) { SizeAndAlignment sizeAndAlignment = SizeofCalculator.getSizeAndAlignment(type, point); if (sizeAndAlignment == null) return VALUE_CANNOT_BE_DETERMINED; return sizeAndAlignment.size; } /** * Tests whether the value is a template parameter (or a parameter pack). * * @return the parameter id of the parameter, or -1 if it is not a template * parameter. */ public static int isTemplateParameter(IValue tval) { ICPPEvaluation eval = tval.getEvaluation(); if (eval instanceof EvalBinding) { return ((EvalBinding) eval).getTemplateParameterID(); } return -1; } /** * Tests whether the value references some template parameter. */ public static boolean referencesTemplateParameter(IValue tval) { ICPPEvaluation eval = tval.getEvaluation(); if (eval == null) return false; return eval.referencesTemplateParameter(); } /** * Tests whether the value depends on a template parameter. */ public static boolean isDependentValue(IValue nonTypeValue) { if (nonTypeValue == null) return false; ICPPEvaluation eval = nonTypeValue.getEvaluation(); return eval != null && eval.isValueDependent(); } /** * Creates the value for an expression. */ public static IValue create(IASTExpression expr, int maxRecursionDepth) { Number val= evaluate(expr, maxRecursionDepth); if (val == VALUE_CANNOT_BE_DETERMINED) return UNKNOWN; if (val != null) return create(val.longValue()); if (expr instanceof ICPPASTInitializerClause) { ICPPEvaluation evaluation = ((ICPPASTInitializerClause) expr).getEvaluation(); return new Value(null, evaluation); } return UNKNOWN; } /** * Creates a value off its canonical representation. */ public static IValue fromInternalRepresentation(ICPPEvaluation evaluation) { return new Value(null, evaluation); } /** * 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(CharArrayUtils.extractChars(buf), null); } /** * Computes the canonical representation of the value of the expression. * Returns a {@code Number} for numerical values or {@code null}, otherwise. * @throws UnknownValueException */ private static Number evaluate(IASTExpression exp, int maxdepth) { if (maxdepth < 0 || exp == null) return VALUE_CANNOT_BE_DETERMINED; if (exp instanceof IASTArraySubscriptExpression) { return VALUE_CANNOT_BE_DETERMINED; } if (exp instanceof IASTBinaryExpression) { return evaluateBinaryExpression((IASTBinaryExpression) exp, maxdepth); } if (exp instanceof IASTCastExpression) { // must be ahead of unary return evaluate(((IASTCastExpression) exp).getOperand(), maxdepth); } if (exp instanceof IASTUnaryExpression) { return evaluateUnaryExpression((IASTUnaryExpression) exp, maxdepth); } if (exp instanceof IASTConditionalExpression) { IASTConditionalExpression cexpr= (IASTConditionalExpression) exp; Number v= evaluate(cexpr.getLogicalConditionExpression(), maxdepth); if (v == null || v == VALUE_CANNOT_BE_DETERMINED) return v; if (v.longValue() == 0) { return evaluate(cexpr.getNegativeResultExpression(), maxdepth); } final IASTExpression pe = cexpr.getPositiveResultExpression(); if (pe == null) // gnu-extension allows to omit the positive expression. return v; return evaluate(pe, maxdepth); } if (exp instanceof IASTIdExpression) { IBinding b= ((IASTIdExpression) exp).getName().resolvePreBinding(); return evaluateBinding(b, maxdepth); } if (exp instanceof IASTLiteralExpression) { IASTLiteralExpression litEx= (IASTLiteralExpression) exp; switch (litEx.getKind()) { case IASTLiteralExpression.lk_false: case IASTLiteralExpression.lk_nullptr: return Long.valueOf(0); case IASTLiteralExpression.lk_true: return Long.valueOf(1); case IASTLiteralExpression.lk_integer_constant: try { return ExpressionEvaluator.getNumber(litEx.getValue()); } catch (EvalException e) { return VALUE_CANNOT_BE_DETERMINED; } 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 e) { return VALUE_CANNOT_BE_DETERMINED; } } } if (exp instanceof IASTTypeIdExpression) { IASTTypeIdExpression typeIdExp = (IASTTypeIdExpression) exp; ASTTranslationUnit ast = (ASTTranslationUnit) exp.getTranslationUnit(); final IType type = ast.createType(typeIdExp.getTypeId()); if (type instanceof ICPPUnknownType) return null; return applyUnaryTypeIdOperator(typeIdExp.getOperator(), type, exp); } if (exp instanceof IASTBinaryTypeIdExpression) { IASTBinaryTypeIdExpression typeIdExp = (IASTBinaryTypeIdExpression) exp; ASTTranslationUnit ast = (ASTTranslationUnit) exp.getTranslationUnit(); IType t1= ast.createType(typeIdExp.getOperand1()); IType t2= ast.createType(typeIdExp.getOperand2()); if (CPPTemplates.isDependentType(t1) || CPPTemplates.isDependentType(t2)) return null; return applyBinaryTypeIdOperator(typeIdExp.getOperator(), t1, t2, exp); } if (exp instanceof IASTFunctionCallExpression) { return null; // The value will be obtained from the evaluation. } return VALUE_CANNOT_BE_DETERMINED; } /** * Extract a value off a binding. */ private static Number evaluateBinding(IBinding b, int maxdepth) { if (b instanceof IType) { return VALUE_CANNOT_BE_DETERMINED; } if (b instanceof ICPPTemplateNonTypeParameter) { return null; } if (b instanceof ICPPUnknownBinding) { return null; } 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 && value != Value.UNKNOWN) { return value.numericalValue(); } return VALUE_CANNOT_BE_DETERMINED; } private static Number evaluateUnaryExpression(IASTUnaryExpression exp, int maxdepth) { final int unaryOp= exp.getOperator(); if (unaryOp == IASTUnaryExpression.op_sizeof) { final IASTExpression operand = exp.getOperand(); if (operand != null) { IType type = operand.getExpressionType(); if (type instanceof ICPPUnknownType) return null; ASTTranslationUnit ast = (ASTTranslationUnit) exp.getTranslationUnit(); SizeofCalculator calculator = ast.getSizeofCalculator(); SizeAndAlignment info = calculator.sizeAndAlignment(type); if (info != null) return info.size; } return VALUE_CANNOT_BE_DETERMINED; } if (unaryOp == IASTUnaryExpression.op_amper || unaryOp == IASTUnaryExpression.op_star || unaryOp == IASTUnaryExpression.op_sizeofParameterPack) { return VALUE_CANNOT_BE_DETERMINED; } final Number value= evaluate(exp.getOperand(), maxdepth); if (value == null || value == VALUE_CANNOT_BE_DETERMINED) return value; return applyUnaryOperator(unaryOp, value.longValue()); } private static Number applyUnaryOperator(final int unaryOp, final long value) { switch (unaryOp) { case IASTUnaryExpression.op_bracketedPrimary: case IASTUnaryExpression.op_plus: return value; } switch (unaryOp) { case IASTUnaryExpression.op_prefixIncr: case IASTUnaryExpression.op_postFixIncr: return value + 1; case IASTUnaryExpression.op_prefixDecr: case IASTUnaryExpression.op_postFixDecr: return value - 1; case IASTUnaryExpression.op_minus: return -value; case IASTUnaryExpression.op_tilde: return ~value; case IASTUnaryExpression.op_not: return value == 0 ? 1 : 0; } return VALUE_CANNOT_BE_DETERMINED; } private static Number evaluateBinaryExpression(IASTBinaryExpression exp, int maxdepth) { final int op= exp.getOperator(); switch (op) { case IASTBinaryExpression.op_equals: if (exp.getOperand1().equals(exp.getOperand2())) return Long.valueOf(1); break; case IASTBinaryExpression.op_notequals: if (exp.getOperand1().equals(exp.getOperand2())) return Long.valueOf(0); break; } final Number o1= evaluate(exp.getOperand1(), maxdepth); if (o1 == null || o1 == VALUE_CANNOT_BE_DETERMINED) return o1; final Number o2= evaluate(exp.getOperand2(), maxdepth); if (o2 == null || o2 == VALUE_CANNOT_BE_DETERMINED) return o2; return applyBinaryOperator(op, o1.longValue(), o2.longValue()); } private static Number applyBinaryOperator(final int op, final long v1, final long v2) { switch (op) { case IASTBinaryExpression.op_multiply: return v1 * v2; case IASTBinaryExpression.op_divide: if (v2 == 0) return VALUE_CANNOT_BE_DETERMINED; return v1 / v2; case IASTBinaryExpression.op_modulo: if (v2 == 0) return VALUE_CANNOT_BE_DETERMINED; 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); } return VALUE_CANNOT_BE_DETERMINED; } /** * Parses a long, returns null 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; } /** * Converts long to a char array */ private static char[] toCharArray(long value) { StringBuilder buf= new StringBuilder(); buf.append(value); return CharArrayUtils.extractChars(buf); } }