/******************************************************************************* * Copyright (c) 2008, 2014 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.Arrays; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; 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.pdom.dom.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 IntegralValue implements IValue { public static final int MAX_RECURSION_DEPTH = 25; // IntegralValue.THIS represents the this pointer inside a member function / constructor. public static final IntegralValue THIS = new IntegralValue("this".toCharArray()); //$NON-NLS-1$ // IntegralValue.UNKNOWN indicates general inability to determine a value. It doesn't have to be an error, // it could be that evaluation ran into a performance limit, or that we can't model this kind of // value (such as a pointer to a function). public static final IntegralValue UNKNOWN = new IntegralValue("<unknown>".toCharArray()) { //$NON-NLS-1$ @Override public void setSubValue(int position, ICPPEvaluation newValue) { throw new UnsupportedOperationException(); } }; // IntegralValue.ERROR indicates that an error, such as a substitution failure, occurred during evaluation. public static final IntegralValue ERROR= new IntegralValue("<error>".toCharArray()); //$NON-NLS-1$ public static final IntegralValue NOT_INITIALIZED= new IntegralValue("<__>".toCharArray()); //$NON-NLS-1$ private static final char UNIQUE_CHAR = '_'; private final static IntegralValue[] TYPICAL= { new IntegralValue(new char[] {'0'}), new IntegralValue(new char[] {'1'}), new IntegralValue(new char[] {'2'}), new IntegralValue(new char[] {'3'}), new IntegralValue(new char[] {'4'}), new IntegralValue(new char[] {'5'}), new IntegralValue(new char[] {'6'})}; private static int sUnique= 0; // The following invariant always holds: (fFixedValue == null) != (fEvaluation == null) private final char[] fFixedValue; private IntegralValue(char[] fixedValue) { fFixedValue = fixedValue; } @Override public Long numericalValue() { return (Long) numberValue(); // IntegralValue.numberValue() always returns a Long } @Override public final Number numberValue() { return parseLong(fFixedValue); } @Override public ICPPEvaluation getEvaluation() { return null; } @Override public final char[] getSignature() { return fFixedValue; } @Deprecated @Override public char[] getInternalExpression() { return CharArrayUtils.EMPTY_CHAR_ARRAY; } @Deprecated @Override public IBinding[] getUnknownBindings() { return IBinding.EMPTY_BINDING_ARRAY; } @Override public void marshal(ITypeMarshalBuffer buf) throws CoreException { if (UNKNOWN == this) { buf.putShort((short) (ITypeMarshalBuffer.INTEGRAL_VALUE | ITypeMarshalBuffer.FLAG1)); } else if (THIS == this) { buf.putShort((short) (ITypeMarshalBuffer.INTEGRAL_VALUE | ITypeMarshalBuffer.FLAG5)); } else { Number num= numberValue(); if (num != null) { long lv= num.longValue(); if (lv >= 0) { buf.putShort((short) (ITypeMarshalBuffer.INTEGRAL_VALUE | ITypeMarshalBuffer.FLAG2)); buf.putLong(lv); } else { buf.putShort((short) (ITypeMarshalBuffer.INTEGRAL_VALUE | ITypeMarshalBuffer.FLAG3)); buf.putLong(-lv); } } else { buf.putShort((short) (ITypeMarshalBuffer.INTEGRAL_VALUE | ITypeMarshalBuffer.FLAG4)); buf.putCharArray(fFixedValue); } } } public static IValue unmarshal(short firstBytes, ITypeMarshalBuffer buf) throws CoreException { if (firstBytes == TypeMarshalBuffer.NULL_TYPE) return IntegralValue.UNKNOWN; if ((firstBytes & ITypeMarshalBuffer.FLAG1) != 0) return IntegralValue.UNKNOWN; if ((firstBytes & ITypeMarshalBuffer.FLAG2) != 0) return IntegralValue.create(buf.getLong()); if ((firstBytes & ITypeMarshalBuffer.FLAG3) != 0) return IntegralValue.create(-buf.getLong()); if ((firstBytes & ITypeMarshalBuffer.FLAG4) != 0) return new IntegralValue(buf.getCharArray()); if ((firstBytes & ITypeMarshalBuffer.FLAG5) != 0) return IntegralValue.THIS; return IntegralValue.UNKNOWN; } @Override public int hashCode() { return CharArrayUtils.hash(getSignature()); } @Override public boolean equals(Object obj) { if (!(obj instanceof IntegralValue)) { return false; } final IntegralValue rhs = (IntegralValue) obj; return CharArrayUtils.equals(getSignature(), rhs.getSignature()); } /** * For debugging only. */ @Override public String toString() { return new String(getSignature()); } /** * Creates a value representing the given number. */ public static IntegralValue create(long value) { if (value >= 0 && value < TYPICAL.length) return TYPICAL[(int) value]; return new IntegralValue(toCharArray(value)); } /** * Creates a value object representing the given boolean value. */ public static IntegralValue create(boolean value) { return create(value ? 1 : 0); } public static IValue incrementedValue(IValue value, int increment) { if (value == UNKNOWN) return UNKNOWN; Number val = value.numberValue(); if (val != null) { return create(val.longValue() + increment); } ICPPEvaluation arg1 = value.getEvaluation(); EvalFixed arg2 = new EvalFixed(CPPBasicType.INT, ValueCategory.PRVALUE, create(increment)); return DependentValue.create(new EvalBinary(IASTBinaryExpression.op_plus, arg1, arg2, arg1.getTemplateDefinition())); } /** * Tests whether the value is a template parameter (or a parameter pack). * * @return the parameter id of the parameter, or <code>-1</code> 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 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 IntegralValue(CharArrayUtils.extractChars(buf)); } /** * 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; } /** * Converts long to a char array */ private static char[] toCharArray(long value) { StringBuilder buf= new StringBuilder(); buf.append(value); return CharArrayUtils.extractChars(buf); } @Override public final int numberOfSubValues() { return 1; } @Override public final ICPPEvaluation getSubValue(int index) { return EvalFixed.INCOMPLETE; } @Override public final ICPPEvaluation[] getAllSubValues() { return new ICPPEvaluation[] { getEvaluation() }; } @Override public void setSubValue(int position, ICPPEvaluation newValue) { throw new IllegalStateException("Trying to set incomplete value"); //$NON-NLS-1$ } @Override public IValue clone() { return new IntegralValue(Arrays.copyOf(fFixedValue, fFixedValue.length)); } }