/*******************************************************************************
 * Copyright (c) 2006, 2015 Wind River Systems, Inc. and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     Anton Leherbauer (Wind River Systems) - initial API and implementation
 *     Markus Schorn (Wind River Systems)
 *     Sergey Prigogin (Google)
 *     Marc-Andre Laperle (Ericsson)
 *******************************************************************************/
package org.eclipse.cdt.internal.core.model;

import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
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.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpressionList;
import org.eclipse.cdt.core.dom.ast.IASTFieldDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTInitializerList;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTPointer;
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.c.ICASTDesignatedInitializer;
import org.eclipse.cdt.core.dom.ast.c.ICASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.c.ICASTTypeIdInitializerExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDecltypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDesignatedInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTPackExpansionExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTPointerToMember;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplatedTypeTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeTransformationSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.gnu.IGNUASTCompoundStatementExpression;
import org.eclipse.cdt.core.dom.ast.gnu.c.ICASTKnRFunctionDeclarator;
import org.eclipse.cdt.core.parser.GCCKeywords;
import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;

/**
 * This is a utility class to help convert AST elements to strings.
 *
 * @see org.eclipse.cdt.core.dom.ast.ASTTypeUtil
 */
public class ASTStringUtil {
	private static final String SPACE = " "; //$NON-NLS-1$
	private static final String COMMA_SPACE = ", "; //$NON-NLS-1$
	private static final String[] EMPTY_STRING_ARRAY = {};

	/**
	 * Return the qualified name if the given <code>IASTName</code>
	 * is an <code>ICPPASTQualifiedName</code>, otherwise a simple name is returned.
	 *
	 * @param name
	 * @return a (possibly) qualified name
	 */
	public static String getQualifiedName(IASTName name) {
		return appendQualifiedNameString(new StringBuilder(), name).toString();
	}

	/**
	 * Return the non-qualified name.
	 *
	 * @param name
	 * @return a non-qualified name
	 */
	public static String getSimpleName(IASTName name) {
		return appendSimpleNameString(new StringBuilder(), name).toString();
	}

	/**
	 * Compute a signature string with parameters, without initializers.
	 */
	public static String getSignatureString(IASTDeclarator declarator) {
		return trimRight(appendSignatureString(new StringBuilder(), declarator)).toString();
	}

	/**
	 * Compute a signature string including parameters, but without initializers.
	 *
	 * @param declSpecifier
	 * @param declarator
	 * @return the signature string
	 */
	public static String getSignatureString(IASTDeclSpecifier declSpecifier, IASTDeclarator declarator) {
		final StringBuilder buffer = new StringBuilder();
		appendDeclarationString(buffer, declSpecifier, declarator, null);
		return trimRight(buffer).toString();
	}

	/**
	 * Compute the return-type string for a function declarator.
	 *
	 * @param declSpecifier
	 * @param fdecl
	 * @return the return type string
	 */
	public static String getReturnTypeString(IASTDeclSpecifier declSpecifier, IASTFunctionDeclarator fdecl) {
		final StringBuilder buffer = new StringBuilder();
		final IASTDeclarator declarator = ASTQueries.findOutermostDeclarator(fdecl);
		appendDeclarationString(buffer, declSpecifier, declarator, fdecl);
		return trimRight(buffer).toString();
	}

	/**
	 * Get the signatures of the function parameter declarations.
	 *
	 * @param functionDeclarator
	 * @return the parameter signature array
	 */
	public static String[] getParameterSignatureArray(IASTFunctionDeclarator functionDeclarator) {
		if (functionDeclarator instanceof IASTStandardFunctionDeclarator) {
			final IASTStandardFunctionDeclarator standardFunctionDecl = (IASTStandardFunctionDeclarator) functionDeclarator;
			final IASTParameterDeclaration[] parameters = standardFunctionDecl.getParameters();
			final boolean takesVarArgs = standardFunctionDecl.takesVarArgs();
			final String[] parameterStrings = new String[parameters.length + (takesVarArgs ? 1 : 0)];
			int i;
			for (i = 0; i < parameters.length; ++i) {
				parameterStrings[i] = getParameterSignatureString(parameters[i]);
			}
			if (takesVarArgs) {
				parameterStrings[i] = new String(Keywords.cpELLIPSIS);
			}
			return parameterStrings;
		} else if (functionDeclarator instanceof ICASTKnRFunctionDeclarator) {
			final ICASTKnRFunctionDeclarator knrDeclarator = (ICASTKnRFunctionDeclarator) functionDeclarator;
			final IASTName[] names = knrDeclarator.getParameterNames();
			final String[] result = new String[names.length];
			for (int i = 0; i < names.length; i++) {
				if (names[i] != null) {
					final IASTDeclarator declaratorForParameterName = knrDeclarator
							.getDeclaratorForParameterName(names[i]);
					if (declaratorForParameterName != null) {
						result[i] = getSignatureString(declaratorForParameterName);
					} else {
						result[i] = "?"; //$NON-NLS-1$
					}
				}
			}
			return result;
		}
		return EMPTY_STRING_ARRAY;
	}

	/**
	 * Convert the given template parameters into a string array.
	 *
	 * @param templateParams
	 * @return a string array of template parameters
	 */
	public static String[] getTemplateParameterArray(ICPPASTTemplateParameter[] templateParams) {
		final String[] parameterTypes = new String[templateParams.length];
		for (int i = 0; i < templateParams.length; i++) {
			final StringBuilder paramType = new StringBuilder();
			final ICPPASTTemplateParameter parameter = templateParams[i];
			appendTemplateParameterString(paramType, parameter);
			parameterTypes[i] = trimRight(paramType).toString();
		}
		return parameterTypes;
	}

	/**
	 * Returns a string representation for the given expression
	 */
	public static String getExpressionString(IASTExpression expression) {
		StringBuilder buf = new StringBuilder();
		return appendExpressionString(buf, expression).toString();
	}

	public static String getInitializerString(IASTInitializer init) {
		StringBuilder buf = new StringBuilder();
		return appendInitializerString(buf, init).toString();
	}

	/**
	 * Joins strings together using a given delimiter.
	 * @param strings the strings to join.
	 * @param delimiter the delimiter that is put between the strings when joining them.
	 * @return the joined string.
	 */
	public static String join(String[] strings, CharSequence delimiter) {
		if (strings.length == 0) {
			return ""; //$NON-NLS-1$
		} else if (strings.length == 1) {
			return strings[0];
		} else {
			StringBuilder buf = new StringBuilder(strings[0]);
			for (int i = 1; i < strings.length; i++) {
				buf.append(delimiter);
				buf.append(strings[i]);
			}
			return buf.toString();
		}
	}

	private static String getParameterSignatureString(IASTParameterDeclaration parameterDeclaration) {
		return trimRight(appendParameterDeclarationString(new StringBuilder(), parameterDeclaration)).toString();
	}

	private static StringBuilder appendSignatureString(StringBuilder buffer, IASTDeclarator declarator) {
		// get the declaration node
		IASTNode node = declarator.getParent();
		while (node instanceof IASTDeclarator) {
			declarator = (IASTDeclarator) node;
			node = node.getParent();
		}

		// get the declSpec
		final IASTDeclSpecifier declSpec;
		if (node instanceof IASTParameterDeclaration) {
			declSpec = ((IASTParameterDeclaration) node).getDeclSpecifier();
		} else if (node instanceof IASTSimpleDeclaration) {
			declSpec = ((IASTSimpleDeclaration) node).getDeclSpecifier();
		} else if (node instanceof IASTFunctionDefinition) {
			declSpec = ((IASTFunctionDefinition) node).getDeclSpecifier();
		} else if (node instanceof IASTTypeId) {
			declSpec = ((IASTTypeId) node).getDeclSpecifier();
		} else {
			declSpec = null;
		}

		return appendDeclarationString(buffer, declSpec, declarator, null);
	}

	private static StringBuilder appendDeclarationString(StringBuilder buffer, IASTDeclSpecifier declSpecifier,
			IASTDeclarator declarator, IASTFunctionDeclarator returnTypeOf) {
		if (declSpecifier != null) {
			appendDeclSpecifierString(buffer, declSpecifier);
			trimRight(buffer);
		}
		appendDeclaratorString(buffer, declarator, false, returnTypeOf);
		return buffer;
	}

	private static StringBuilder appendDeclaratorString(StringBuilder buffer, IASTDeclarator declarator,
			boolean protectPointers, IASTFunctionDeclarator returnTypeOf) {
		if (declarator == null) {
			return buffer;
		}
		final IASTPointerOperator[] ptrs = declarator.getPointerOperators();
		final boolean useParenthesis = protectPointers && ptrs.length > 0;
		if (useParenthesis) {
			buffer.append(Keywords.cpLPAREN);
			protectPointers = false;
		}

		appendPointerOperatorsString(buffer, ptrs);

		if (declarator != returnTypeOf) {
			final IASTDeclarator nestedDeclarator = declarator.getNestedDeclarator();
			if (nestedDeclarator != null) {
				protectPointers = protectPointers || declarator instanceof IASTArrayDeclarator
						|| declarator instanceof IASTFunctionDeclarator || declarator instanceof IASTFieldDeclarator;
				appendDeclaratorString(buffer, nestedDeclarator, protectPointers, returnTypeOf);
			} else if (declarator instanceof ICPPASTDeclarator
					&& ((ICPPASTDeclarator) declarator).declaresParameterPack()) {
				buffer.append(Keywords.cpELLIPSIS);
			}

			if (declarator instanceof IASTArrayDeclarator) {
				appendArrayQualifiersString(buffer, (IASTArrayDeclarator) declarator);
			} else if (declarator instanceof IASTFunctionDeclarator) {
				final IASTFunctionDeclarator functionDecl = (IASTFunctionDeclarator) declarator;
				appendParameterSignatureString(buffer, functionDecl);
				if (declarator instanceof ICPPASTFunctionDeclarator) {
					final ICPPASTFunctionDeclarator cppFunctionDecl = (ICPPASTFunctionDeclarator) declarator;
					if (cppFunctionDecl.isConst()) {
						buffer.append(Keywords.CONST).append(' ');
					}
					if (cppFunctionDecl.isVolatile()) {
						buffer.append(Keywords.VOLATILE).append(' ');
					}
					RefQualifier refQualifier = cppFunctionDecl.getRefQualifier();
					if (refQualifier != null) {
						switch (refQualifier) {
						case LVALUE:
							buffer.append(Keywords.cpAMPER).append(' ');
							break;
						case RVALUE:
							buffer.append(Keywords.cpAND).append(' ');
							break;
						}
					}
					if (cppFunctionDecl.isPureVirtual()) {
						buffer.append("=0 "); //$NON-NLS-1$
					}
					final IASTTypeId[] exceptionTypeIds = cppFunctionDecl.getExceptionSpecification();
					if (exceptionTypeIds != ICPPASTFunctionDeclarator.NO_EXCEPTION_SPECIFICATION) {
						buffer.append(Keywords.THROW).append(" ("); //$NON-NLS-1$
						for (int i = 0; i < exceptionTypeIds.length; i++) {
							if (i > 0) {
								buffer.append(COMMA_SPACE);
							}
							appendTypeIdString(buffer, exceptionTypeIds[i]);
						}
						buffer.append(')');
					}
				}
			} else if (declarator instanceof IASTFieldDeclarator) {
				final IASTFieldDeclarator fieldDeclarator = (IASTFieldDeclarator) declarator;
				final IASTExpression bitFieldSize = fieldDeclarator.getBitFieldSize();
				if (bitFieldSize != null) {
					buffer.append(Keywords.cpCOLON);
					appendExpressionString(buffer, bitFieldSize);
				}
			} else {
				// just a nested name
			}
		}
		if (useParenthesis) {
			trimRight(buffer);
			buffer.append(Keywords.cpRPAREN);
		}
		return buffer;
	}

	private static StringBuilder appendInitializerString(StringBuilder buffer, IASTInitializer initializer) {
		if (initializer instanceof IASTEqualsInitializer) {
			final IASTEqualsInitializer initializerExpression = (IASTEqualsInitializer) initializer;
			buffer.append(Keywords.cpASSIGN);
			appendInitClauseString(buffer, initializerExpression.getInitializerClause());
		} else if (initializer instanceof IASTInitializerList) {
			final IASTInitializerList initializerList = (IASTInitializerList) initializer;
			final IASTInitializerClause[] initializers = initializerList.getClauses();
			buffer.append(Keywords.cpASSIGN);
			buffer.append(Keywords.cpLBRACE);
			for (int i = 0; i < initializers.length; i++) {
				if (i > 0) {
					buffer.append(COMMA_SPACE);
				}
				appendInitClauseString(buffer, initializers[i]);
			}
			trimRight(buffer);
			buffer.append(Keywords.cpRBRACE);
		} else if (initializer instanceof ICASTDesignatedInitializer
				|| initializer instanceof ICPPASTDesignatedInitializer) {
			//TODO handle ICASTDesignatedInitializer?
			//			final ICASTDesignatedInitializer designatedInitializer= (ICASTDesignatedInitializer) initializer;
			//			final ICASTDesignator[] designator= designatedInitializer.getDesignators();
		} else if (initializer instanceof ICPPASTConstructorInitializer) {
			final ICPPASTConstructorInitializer constructorInitializer = (ICPPASTConstructorInitializer) initializer;
			final IASTInitializerClause[] clauses = constructorInitializer.getArguments();
			buffer.append(Keywords.cpLPAREN);
			for (int i = 0; i < clauses.length; i++) {
				if (i > 0) {
					buffer.append(COMMA_SPACE);
				}
				appendInitClauseString(buffer, clauses[i]);
			}
			trimRight(buffer);
			buffer.append(Keywords.cpRPAREN);
		} else if (initializer != null) {
			assert false : "TODO: handle " + initializer.getClass().getName(); //$NON-NLS-1$
		}
		return buffer;
	}

	private static StringBuilder appendInitClauseString(StringBuilder buffer, IASTInitializerClause initializerClause) {
		if (initializerClause instanceof IASTExpression) {
			return appendExpressionString(buffer, (IASTExpression) initializerClause);
		}
		if (initializerClause instanceof IASTInitializer) {
			return appendInitializerString(buffer, (IASTInitializer) initializerClause);
		}
		return buffer;
	}

	private static StringBuilder appendTypeIdString(StringBuilder buffer, IASTTypeId typeId) {
		appendDeclSpecifierString(buffer, typeId.getDeclSpecifier());
		appendDeclaratorString(buffer, typeId.getAbstractDeclarator(), false, null);
		if (typeId instanceof ICPPASTTypeId && ((ICPPASTTypeId) typeId).isPackExpansion())
			buffer.append(Keywords.cpELLIPSIS);
		return buffer;
	}

	private static StringBuilder trimRight(StringBuilder buffer) {
		int length = buffer.length();
		while (length > 0 && buffer.charAt(length - 1) == ' ') {
			--length;
		}
		buffer.setLength(length);
		return buffer;
	}

	private static StringBuilder appendArrayQualifiersString(StringBuilder buffer, IASTArrayDeclarator declarator) {
		final IASTArrayModifier[] modifiers = declarator.getArrayModifiers();
		final int count = modifiers.length;
		for (int i = 0; i < count; i++) {
			buffer.append(Keywords.cpLBRACKET).append(Keywords.cpRBRACKET);
		}
		return buffer;
	}

	private static StringBuilder appendPointerOperatorsString(StringBuilder buffer,
			IASTPointerOperator[] pointerOperators) {
		for (final IASTPointerOperator pointerOperator : pointerOperators) {
			if (pointerOperator instanceof IASTPointer) {
				final IASTPointer pointer = (IASTPointer) pointerOperator;
				if (pointer instanceof ICPPASTPointerToMember) {
					final ICPPASTPointerToMember pointerToMember = (ICPPASTPointerToMember) pointer;
					appendQualifiedNameString(buffer, pointerToMember.getName());
				}
				buffer.append(Keywords.cpSTAR);
				if (pointer.isConst()) {
					buffer.append(' ').append(Keywords.CONST);
				}
				if (pointer.isVolatile()) {
					buffer.append(' ').append(Keywords.VOLATILE);
				}
				if (pointer.isRestrict()) {
					buffer.append(' ').append(Keywords.RESTRICT);
				}
			} else if (pointerOperator instanceof ICPPASTReferenceOperator) {
				if (((ICPPASTReferenceOperator) pointerOperator).isRValueReference()) {
					buffer.append(Keywords.cpAND);
				} else {
					buffer.append(Keywords.cpAMPER);
				}
			}
		}
		return buffer;
	}

	private static StringBuilder appendParameterSignatureString(StringBuilder buffer,
			IASTFunctionDeclarator functionDeclarator) {
		if (functionDeclarator instanceof IASTStandardFunctionDeclarator) {
			final IASTStandardFunctionDeclarator standardFunctionDecl = (IASTStandardFunctionDeclarator) functionDeclarator;
			final IASTParameterDeclaration[] parameters = standardFunctionDecl.getParameters();
			final boolean takesVarArgs = standardFunctionDecl.takesVarArgs();
			buffer.append(Keywords.cpLPAREN);
			for (int i = 0; i < parameters.length; i++) {
				if (i > 0) {
					buffer.append(COMMA_SPACE);
				}
				appendParameterDeclarationString(buffer, parameters[i]);
			}
			if (takesVarArgs) {
				if (parameters.length > 0) {
					buffer.append(COMMA_SPACE);
				}
				buffer.append(Keywords.cpELLIPSIS);
			}
			trimRight(buffer);
			buffer.append(Keywords.cpRPAREN);
		} else if (functionDeclarator instanceof ICASTKnRFunctionDeclarator) {
			buffer.append(Keywords.cpLPAREN);
			final ICASTKnRFunctionDeclarator knrDeclarator = (ICASTKnRFunctionDeclarator) functionDeclarator;
			final IASTName[] names = knrDeclarator.getParameterNames();
			for (int i = 0; i < names.length; i++) {
				if (i > 0) {
					buffer.append(COMMA_SPACE);
				}
				if (names[i] != null) {
					final IASTDeclarator declaratorForParameterName = knrDeclarator
							.getDeclaratorForParameterName(names[i]);
					if (declaratorForParameterName != null) {
						appendSignatureString(buffer, declaratorForParameterName);
					}
				}
			}
			trimRight(buffer);
			buffer.append(Keywords.cpRPAREN);
		}
		return buffer;
	}

	private static StringBuilder appendParameterDeclarationString(StringBuilder buffer,
			IASTParameterDeclaration parameter) {
		final IASTDeclSpecifier declSpecifier = parameter.getDeclSpecifier();
		if (declSpecifier != null) {
			appendDeclSpecifierString(buffer, declSpecifier);
			trimRight(buffer);
		}
		final IASTDeclarator declarator = parameter.getDeclarator();
		if (declarator != null) {
			appendDeclaratorString(buffer, declarator, false, null);
			appendInitializerString(buffer, declarator.getInitializer());
		}
		return buffer;
	}

	private static StringBuilder appendDeclSpecifierString(StringBuilder buffer, IASTDeclSpecifier declSpecifier) {
		if (declSpecifier.isConst()) {
			buffer.append(Keywords.CONST).append(' ');
		}
		if (declSpecifier.isVolatile()) {
			buffer.append(Keywords.VOLATILE).append(' ');
		}
		//		if (declSpecifier.isInline()) {
		//			buffer.append(Keywords.INLINE).append(' ');
		//		}
		//		if (declSpecifier instanceof ICASTDeclSpecifier) {
		//			final ICASTDeclSpecifier cDeclSpec= (ICASTDeclSpecifier) declSpecifier;
		//			if (cDeclSpec.isRestrict()) {
		//				buffer.append(Keywords.RESTRICT).append(' ');
		//			}
		//		} else if (declSpecifier instanceof ICPPASTDeclSpecifier) {
		//			final ICPPASTDeclSpecifier cppDeclSpec= (ICPPASTDeclSpecifier) declSpecifier;
		//			if (cppDeclSpec.isFriend()) {
		//				buffer.append(Keywords.FRIEND).append(' ');
		//			}
		//			if (cppDeclSpec.isVirtual()) {
		//				buffer.append(Keywords.VIRTUAL).append(' ');
		//			}
		//			if (cppDeclSpec.isExplicit()) {
		//				buffer.append(Keywords.EXPLICIT).append(' ');
		//			}
		//			if (declSpecifier instanceof IGPPASTDeclSpecifier) {
		//				final IGPPASTDeclSpecifier gppDeclSpec= (IGPPASTDeclSpecifier) declSpecifier;
		//				if (gppDeclSpec.isRestrict()) {
		//					buffer.append(Keywords.RESTRICT).append(' ');
		//				}
		//			}
		//		}
		// storage class
		//		final int storageClass= declSpecifier.getStorageClass();
		//		switch (storageClass) {
		//		case IASTDeclSpecifier.sc_typedef:
		//			buffer.append(Keywords.TYPEDEF).append(' ');
		//			break;
		//		case IASTDeclSpecifier.sc_extern:
		//			buffer.append(Keywords.EXTERN).append(' ');
		//			break;
		//		case IASTDeclSpecifier.sc_static:
		//			buffer.append(Keywords.STATIC).append(' ');
		//			break;
		//		case IASTDeclSpecifier.sc_auto:
		//			buffer.append(Keywords.AUTO).append(' ');
		//			break;
		//		case IASTDeclSpecifier.sc_register:
		//			buffer.append(Keywords.REGISTER).append(' ');
		//			break;
		//		case ICPPASTDeclSpecifier.sc_mutable:
		//			buffer.append(Keywords.MUTABLE).append(' ');
		//			break;
		//		}
		if (declSpecifier instanceof IASTCompositeTypeSpecifier) {
			final IASTCompositeTypeSpecifier compositeTypeSpec = (IASTCompositeTypeSpecifier) declSpecifier;
			final int key = compositeTypeSpec.getKey();
			switch (key) {
			case IASTCompositeTypeSpecifier.k_struct:
				buffer.append(Keywords.STRUCT).append(' ');
				break;
			case IASTCompositeTypeSpecifier.k_union:
				buffer.append(Keywords.UNION).append(' ');
				break;
			case ICPPASTCompositeTypeSpecifier.k_class:
				buffer.append(Keywords.CLASS).append(' ');
				break;
			default:
			}
			appendQualifiedNameString(buffer, compositeTypeSpec.getName());
		} else if (declSpecifier instanceof IASTElaboratedTypeSpecifier) {
			final IASTElaboratedTypeSpecifier elaboratedTypeSpec = (IASTElaboratedTypeSpecifier) declSpecifier;
			switch (elaboratedTypeSpec.getKind()) {
			case IASTElaboratedTypeSpecifier.k_enum:
				buffer.append(Keywords.ENUM).append(' ');
				break;
			case IASTElaboratedTypeSpecifier.k_struct:
				buffer.append(Keywords.STRUCT).append(' ');
				break;
			case IASTElaboratedTypeSpecifier.k_union:
				buffer.append(Keywords.UNION).append(' ');
				break;
			case ICPPASTElaboratedTypeSpecifier.k_class:
				buffer.append(Keywords.CLASS).append(' ');
				break;
			default:
				assert false;
			}
			appendQualifiedNameString(buffer, elaboratedTypeSpec.getName());
		} else if (declSpecifier instanceof IASTEnumerationSpecifier) {
			final IASTEnumerationSpecifier enumerationSpec = (IASTEnumerationSpecifier) declSpecifier;
			buffer.append(Keywords.ENUM).append(' ');
			appendQualifiedNameString(buffer, enumerationSpec.getName());
		} else if (declSpecifier instanceof IASTSimpleDeclSpecifier) {
			final IASTSimpleDeclSpecifier simpleDeclSpec = (IASTSimpleDeclSpecifier) declSpecifier;
			if (simpleDeclSpec.isSigned()) {
				buffer.append(Keywords.SIGNED).append(' ');
			}
			if (simpleDeclSpec.isUnsigned()) {
				buffer.append(Keywords.UNSIGNED).append(' ');
			}
			if (simpleDeclSpec.isShort()) {
				buffer.append(Keywords.SHORT).append(' ');
			}
			if (simpleDeclSpec.isLong()) {
				buffer.append(Keywords.LONG).append(' ');
			}
			if (simpleDeclSpec.isLongLong()) {
				buffer.append(Keywords.LONG_LONG).append(' ');
			}
			if (simpleDeclSpec.isComplex()) {
				buffer.append(Keywords._COMPLEX).append(' ');
			}
			if (simpleDeclSpec.isImaginary()) {
				buffer.append(Keywords._IMAGINARY).append(' ');
			}
			switch (simpleDeclSpec.getType()) {
			case IASTSimpleDeclSpecifier.t_void:
				buffer.append(Keywords.VOID).append(' ');
				break;
			case IASTSimpleDeclSpecifier.t_char:
				buffer.append(Keywords.CHAR).append(' ');
				break;
			case IASTSimpleDeclSpecifier.t_int:
				buffer.append(Keywords.INT).append(' ');
				break;
			case IASTSimpleDeclSpecifier.t_int128:
				buffer.append(GCCKeywords.cp__int128).append(' ');
				break;
			case IASTSimpleDeclSpecifier.t_float:
				buffer.append(Keywords.FLOAT).append(' ');
				break;
			case IASTSimpleDeclSpecifier.t_double:
				buffer.append(Keywords.DOUBLE).append(' ');
				break;
			case IASTSimpleDeclSpecifier.t_float128:
				buffer.append(GCCKeywords.cp__float128).append(' ');
				break;
			case IASTSimpleDeclSpecifier.t_decimal32:
				buffer.append(GCCKeywords.cp_decimal32).append(' ');
				break;
			case IASTSimpleDeclSpecifier.t_decimal64:
				buffer.append(GCCKeywords.cp_decimal64).append(' ');
				break;
			case IASTSimpleDeclSpecifier.t_decimal128:
				buffer.append(GCCKeywords.cp_decimal128).append(' ');
				break;
			case IASTSimpleDeclSpecifier.t_bool:
				if (simpleDeclSpec instanceof ICASTSimpleDeclSpecifier) {
					buffer.append(Keywords.cBOOL).append(' ');
				} else {
					buffer.append(Keywords.BOOL).append(' ');
				}
				break;
			case IASTSimpleDeclSpecifier.t_wchar_t:
				buffer.append(Keywords.WCHAR_T).append(' ');
				break;
			case IASTSimpleDeclSpecifier.t_char16_t:
				buffer.append(Keywords.CHAR16_T).append(' ');
				break;
			case IASTSimpleDeclSpecifier.t_char32_t:
				buffer.append(Keywords.CHAR32_T).append(' ');
				break;
			default:
			}
		} else if (declSpecifier instanceof IASTNamedTypeSpecifier) {
			final IASTNamedTypeSpecifier namedTypeSpec = (IASTNamedTypeSpecifier) declSpecifier;
			appendQualifiedNameString(buffer, namedTypeSpec.getName());
		} else if (declSpecifier instanceof ICPPASTTypeTransformationSpecifier) {
			final ICPPASTTypeTransformationSpecifier typeTransformationSpec = (ICPPASTTypeTransformationSpecifier) declSpecifier;
			switch (typeTransformationSpec.getOperator()) {
			case underlying_type:
				buffer.append(GCCKeywords.cp__underlying_type);
				break;
			default:
			}
			buffer.append('(');
			appendTypeIdString(buffer, typeTransformationSpec.getOperand());
			buffer.append(')');
		}
		return buffer;
	}

	private static StringBuilder appendQualifiedNameString(StringBuilder buffer, IASTName name) {
		return appendNameString(buffer, name, true);
	}

	private static StringBuilder appendDecltypeSpecifier(StringBuilder buffer, ICPPASTDecltypeSpecifier decltypeSpec) {
		buffer.append(Keywords.DECLTYPE);
		buffer.append(Keywords.cpLPAREN);
		appendExpressionString(buffer, decltypeSpec.getDecltypeExpression());
		buffer.append(Keywords.cpRPAREN);
		return buffer;
	}

	private static StringBuilder appendQualifiedNameString(StringBuilder buffer, ICPPASTNameSpecifier nameSpec) {
		if (nameSpec instanceof IASTName) {
			appendQualifiedNameString(buffer, (IASTName) nameSpec);
		} else if (nameSpec instanceof ICPPASTDecltypeSpecifier) {
			appendDecltypeSpecifier(buffer, (ICPPASTDecltypeSpecifier) nameSpec);
		}
		return buffer;
	}

	private static StringBuilder appendSimpleNameString(StringBuilder buffer, IASTName name) {
		return appendNameString(buffer, name, false);
	}

	private static StringBuilder appendNameString(StringBuilder buffer, IASTName name, boolean qualified) {
		if (name instanceof ICPPASTQualifiedName) {
			final ICPPASTQualifiedName qualifiedName = (ICPPASTQualifiedName) name;
			if (qualified) {
				final ICPPASTNameSpecifier[] segments = qualifiedName.getAllSegments();
				for (int i = 0; i < segments.length; i++) {
					if (i > 0) {
						buffer.append(Keywords.cpCOLONCOLON);
					}
					appendQualifiedNameString(buffer, segments[i]);
				}
			} else {
				IASTName lastName = qualifiedName.getLastName();
				appendNameString(buffer, lastName, false);
			}
		} else if (name instanceof ICPPASTTemplateId) {
			final ICPPASTTemplateId templateId = (ICPPASTTemplateId) name;
			appendQualifiedNameString(buffer, templateId.getTemplateName());
			final IASTNode[] templateArguments = templateId.getTemplateArguments();
			buffer.append(Keywords.cpLT);
			for (int i = 0; i < templateArguments.length; i++) {
				if (i > 0) {
					buffer.append(Keywords.cpCOMMA);
				}
				final IASTNode argument = templateArguments[i];
				if (argument instanceof IASTTypeId) {
					appendTypeIdString(buffer, (IASTTypeId) argument);
				} else if (argument instanceof IASTExpression) {
					final IASTExpression expression = (IASTExpression) argument;
					appendExpressionString(buffer, expression);
				}
				trimRight(buffer);
			}
			buffer.append(Keywords.cpGT);
		} else if (name != null) {
			buffer.append(name.getSimpleID());
		}
		return buffer;
	}

	private static StringBuilder appendTemplateParameterString(StringBuilder buffer,
			ICPPASTTemplateParameter parameter) {
		if (parameter instanceof ICPPASTParameterDeclaration) {
			appendParameterDeclarationString(buffer, (ICPPASTParameterDeclaration) parameter);
		} else if (parameter instanceof ICPPASTSimpleTypeTemplateParameter) {
			final ICPPASTSimpleTypeTemplateParameter simpletypeParameter = (ICPPASTSimpleTypeTemplateParameter) parameter;
			final IASTName name = simpletypeParameter.getName();
			if (name != null) {
				appendSimpleNameString(buffer, name);
			} else {
				final int type = simpletypeParameter.getParameterType();
				switch (type) {
				case ICPPASTSimpleTypeTemplateParameter.st_class:
					buffer.append(Keywords.CLASS);
					break;
				case ICPPASTSimpleTypeTemplateParameter.st_typename:
					buffer.append(Keywords.TYPENAME);
					break;
				}
			}
		} else if (parameter instanceof ICPPASTTemplatedTypeTemplateParameter) {
			final ICPPASTTemplatedTypeTemplateParameter templatedTypeParameter = (ICPPASTTemplatedTypeTemplateParameter) parameter;
			final ICPPASTTemplateParameter[] subParameters = templatedTypeParameter.getTemplateParameters();
			buffer.append(Keywords.TEMPLATE).append(Keywords.cpLT);
			for (int i = 0; i < subParameters.length; i++) {
				final ICPPASTTemplateParameter templateParameter = subParameters[i];
				if (i > 0) {
					buffer.append(COMMA_SPACE);
				}
				appendTemplateParameterString(buffer, templateParameter);
			}
			trimRight(buffer);
			buffer.append(Keywords.cpGT);
		}
		return buffer;
	}

	private static StringBuilder appendExpressionString(StringBuilder buffer, IASTExpression expression) {
		if (expression instanceof IASTIdExpression) {
			final IASTIdExpression idExpression = (IASTIdExpression) expression;
			return appendQualifiedNameString(buffer, idExpression.getName());
		}
		if (expression instanceof IASTExpressionList) {
			final IASTExpressionList expressionList = (IASTExpressionList) expression;
			final IASTExpression[] expressions = expressionList.getExpressions();
			for (int i = 0; i < expressions.length; i++) {
				if (i > 0) {
					buffer.append(COMMA_SPACE);
				}
				appendExpressionString(buffer, expressions[i]);
			}
			return buffer;
		}
		if (expression instanceof ICPPASTSimpleTypeConstructorExpression) {
			final ICPPASTSimpleTypeConstructorExpression typeCast = (ICPPASTSimpleTypeConstructorExpression) expression;
			appendDeclSpecifierString(buffer, typeCast.getDeclSpecifier());
			trimRight(buffer);
			return appendInitializerString(buffer, typeCast.getInitializer());
		}
		if (expression instanceof IASTArraySubscriptExpression)
			return appendArraySubscriptExpression(buffer, (IASTArraySubscriptExpression) expression);
		if (expression instanceof IASTBinaryExpression)
			return appendBinaryExpression(buffer, (IASTBinaryExpression) expression);
		if (expression instanceof IASTCastExpression)
			return appendCastExpression(buffer, (IASTCastExpression) expression);
		if (expression instanceof IASTConditionalExpression)
			return appendConditionalExpression(buffer, (IASTConditionalExpression) expression);
		if (expression instanceof IASTExpressionList)
			return appendExpressionList(buffer, (IASTExpressionList) expression);
		if (expression instanceof IASTFieldReference)
			return appendFieldReference(buffer, (IASTFieldReference) expression);
		if (expression instanceof IASTFunctionCallExpression)
			return appendFunctionCallExpression(buffer, (IASTFunctionCallExpression) expression);
		if (expression instanceof IASTLiteralExpression)
			return appendLiteralExpression(buffer, (IASTLiteralExpression) expression);
		if (expression instanceof IASTTypeIdExpression)
			return appendTypeIdExpression(buffer, (IASTTypeIdExpression) expression);
		if (expression instanceof IASTUnaryExpression)
			return appendUnaryExpression(buffer, (IASTUnaryExpression) expression);
		if (expression instanceof ICASTTypeIdInitializerExpression)
			return appendTypeIdInitializerExpression(buffer, (ICASTTypeIdInitializerExpression) expression);
		if (expression instanceof ICPPASTDeleteExpression)
			return appendDeleteExpression(buffer, (ICPPASTDeleteExpression) expression);
		if (expression instanceof ICPPASTNewExpression)
			return appendNewExpression(buffer, (ICPPASTNewExpression) expression);
		if (expression instanceof IGNUASTCompoundStatementExpression)
			return appendCompoundStatementExpression(buffer, (IGNUASTCompoundStatementExpression) expression);
		if (expression instanceof ICPPASTPackExpansionExpression)
			return appendPackExpansionExpression(buffer, (ICPPASTPackExpansionExpression) expression);

		return buffer;
	}

	private static StringBuilder appendArraySubscriptExpression(StringBuilder buffer,
			IASTArraySubscriptExpression expression) {
		appendExpressionString(buffer, expression.getArrayExpression());
		buffer.append(Keywords.cpLBRACKET);
		appendInitClauseString(buffer, expression.getArgument());
		return buffer.append(Keywords.cpRBRACKET);
	}

	private static StringBuilder appendCastExpression(StringBuilder buffer, IASTCastExpression expression) {
		if ((expression.getOperator() == IASTCastExpression.op_cast)) {
			buffer.append(Keywords.cpLPAREN);
			appendTypeIdString(buffer, expression.getTypeId());
			buffer.append(Keywords.cpRPAREN);
			return appendExpressionString(buffer, expression.getOperand());
		}

		buffer.append(getCastOperatorString(expression));
		buffer.append(Keywords.cpLT);
		appendTypeIdString(buffer, expression.getTypeId());
		trimRight(buffer);
		buffer.append(Keywords.cpGT);
		buffer.append(Keywords.cpLPAREN);
		appendExpressionString(buffer, expression.getOperand());
		return buffer.append(Keywords.cpRPAREN);
	}

	private static StringBuilder appendFieldReference(StringBuilder buffer, IASTFieldReference expression) {
		appendExpressionString(buffer, expression.getFieldOwner());
		buffer.append(expression.isPointerDereference() ? Keywords.cpARROW : Keywords.cpDOT);

		return appendNameString(buffer, expression.getFieldName(), true);
	}

	private static StringBuilder appendFunctionCallExpression(StringBuilder buffer,
			IASTFunctionCallExpression expression) {
		appendExpressionString(buffer, expression.getFunctionNameExpression());
		buffer.append(Keywords.cpLPAREN);
		IASTInitializerClause[] clauses = expression.getArguments();
		for (int i = 0; i < clauses.length; i++) {
			if (i > 0) {
				buffer.append(COMMA_SPACE);
			}
			appendInitClauseString(buffer, (clauses[i]));
		}
		return buffer.append(Keywords.cpRPAREN);
	}

	private static StringBuilder appendTypeIdInitializerExpression(StringBuilder buffer,
			ICASTTypeIdInitializerExpression expression) {
		buffer.append(Keywords.cpLPAREN);
		appendTypeIdString(buffer, expression.getTypeId());
		buffer.append(Keywords.cpRPAREN);
		return appendInitializerString(buffer, expression.getInitializer());
	}

	private static StringBuilder appendDeleteExpression(StringBuilder buffer, ICPPASTDeleteExpression expression) {
		buffer.append(Keywords.DELETE);
		buffer.append(SPACE);
		return appendExpressionString(buffer, expression.getOperand());
	}

	private static StringBuilder appendCompoundStatementExpression(StringBuilder buffer,
			IGNUASTCompoundStatementExpression expression) {
		buffer.append(Keywords.cpLPAREN).append(Keywords.cpLBRACE);
		buffer.append(Keywords.cpELLIPSIS);
		return buffer.append(Keywords.cpRBRACE).append(Keywords.cpRPAREN);
	}

	private static StringBuilder appendTypeIdExpression(StringBuilder buffer, IASTTypeIdExpression expression) {
		buffer.append(getTypeIdExpressionOperator(expression));
		buffer.append(Keywords.cpLPAREN);
		appendTypeIdString(buffer, expression.getTypeId());
		trimRight(buffer);
		return buffer.append(Keywords.cpRPAREN);
	}

	private static StringBuilder appendExpressionList(StringBuilder buffer, IASTExpressionList expression) {
		IASTExpression[] exps = expression.getExpressions();
		if (exps != null) {
			for (int i = 0; i < exps.length; i++) {
				if (i > 0) {
					buffer.append(COMMA_SPACE);
				}
				appendExpressionString(buffer, exps[i]);
			}
		}
		return buffer;
	}

	private static StringBuilder appendLiteralExpression(StringBuilder buffer, IASTLiteralExpression expression) {
		return buffer.append(expression.toString());
	}

	private static StringBuilder appendConditionalExpression(StringBuilder buffer,
			IASTConditionalExpression expression) {
		appendExpressionString(buffer, expression.getLogicalConditionExpression());
		buffer.append(SPACE);
		buffer.append(Keywords.cpQUESTION);
		buffer.append(SPACE);
		appendExpressionString(buffer, expression.getPositiveResultExpression());
		buffer.append(SPACE);
		buffer.append(Keywords.cpCOLON);
		buffer.append(SPACE);
		return appendExpressionString(buffer, expression.getNegativeResultExpression());
	}

	private static StringBuilder appendNewExpression(StringBuilder buffer, ICPPASTNewExpression expression) {
		buffer.append(Keywords.NEW);
		buffer.append(SPACE);
		final IASTInitializerClause[] args = expression.getPlacementArguments();
		if (args != null) {
			buffer.append(Keywords.cpLPAREN);
			for (int i = 0; i < args.length; i++) {
				if (i != 0) {
					buffer.append(COMMA_SPACE);
				}
				appendInitClauseString(buffer, args[i]);
			}
			buffer.append(Keywords.cpRPAREN);
		}
		appendTypeIdString(buffer, expression.getTypeId());
		return appendInitializerString(buffer, expression.getInitializer());
	}

	private static StringBuilder appendBinaryExpression(StringBuilder buffer, IASTBinaryExpression expression) {
		appendExpressionString(buffer, expression.getOperand1());
		buffer.append(SPACE);
		buffer.append(getBinaryOperatorString(expression));
		buffer.append(SPACE);
		return appendExpressionString(buffer, expression.getOperand2());
	}

	private static StringBuilder appendUnaryExpression(StringBuilder buffer, IASTUnaryExpression expression) {
		boolean postOperator = false;
		boolean primaryBracketed = false;

		switch (expression.getOperator()) {
		case IASTUnaryExpression.op_postFixDecr:
		case IASTUnaryExpression.op_postFixIncr:
			postOperator = true;
			break;
		case IASTUnaryExpression.op_bracketedPrimary:
			primaryBracketed = true;
			break;
		default:
			postOperator = false;
			break;
		}

		if (!postOperator && !primaryBracketed)
			buffer.append(getUnaryOperatorString(expression));

		// Need to add a space to the unary expression if it is a specific operator.
		switch (expression.getOperator()) {
		case IASTUnaryExpression.op_sizeof:
		case ICPPASTUnaryExpression.op_noexcept:
		case ICPPASTUnaryExpression.op_throw:
		case ICPPASTUnaryExpression.op_typeid:
			buffer.append(SPACE);
			break;
		}

		if (primaryBracketed)
			buffer.append(Keywords.cpLPAREN);
		buffer.append(getExpressionString(expression.getOperand()));
		if (primaryBracketed)
			buffer.append(Keywords.cpRPAREN);
		if (postOperator && !primaryBracketed)
			buffer.append(getUnaryOperatorString(expression));

		return buffer;
	}

	public static String getCastOperatorString(IASTCastExpression expression) {
		int op = expression.getOperator();
		switch (op) {
		case ICPPASTCastExpression.op_const_cast:
			return Keywords.CONST_CAST;
		case ICPPASTCastExpression.op_dynamic_cast:
			return Keywords.DYNAMIC_CAST;
		case ICPPASTCastExpression.op_reinterpret_cast:
			return Keywords.REINTERPRET_CAST;
		case ICPPASTCastExpression.op_static_cast:
			return Keywords.STATIC_CAST;
		}
		return ""; //$NON-NLS-1$
	}

	/**
	 * Returns the String representation of the IASTUnaryExpression's operator.
	 *
	 * @param ue
	 * @return the String representation of the IASTUnaryExpression's operator
	 */
	public static char[] getUnaryOperatorString(IASTUnaryExpression ue) {
		int op = ue.getOperator();
		switch (op) {
		case IASTUnaryExpression.op_noexcept:
			return Keywords.cNOEXCEPT;
		case IASTUnaryExpression.op_throw:
			return Keywords.cTHROW;
		case IASTUnaryExpression.op_typeid:
			return Keywords.cTYPEID;
		case IASTUnaryExpression.op_alignOf:
			return Keywords.cALIGNOF;
		case IASTUnaryExpression.op_amper:
			return Keywords.cpAMPER;
		case IASTUnaryExpression.op_minus:
			return Keywords.cpMINUS;
		case IASTUnaryExpression.op_not:
			return Keywords.cpNOT;
		case IASTUnaryExpression.op_plus:
			return Keywords.cpPLUS;
		case IASTUnaryExpression.op_postFixDecr:
		case IASTUnaryExpression.op_prefixDecr:
			return Keywords.cpDECR;
		case IASTUnaryExpression.op_postFixIncr:
		case IASTUnaryExpression.op_prefixIncr:
			return Keywords.cpINCR;
		case IASTUnaryExpression.op_sizeof:
			return Keywords.cSIZEOF;
		case IASTUnaryExpression.op_sizeofParameterPack:
			return Keywords.cSIZEOFPACK;
		case IASTUnaryExpression.op_star:
			return Keywords.cpSTAR;
		case IASTUnaryExpression.op_tilde:
			return Keywords.cpCOMPL;
		}

		return CharArrayUtils.EMPTY;
	}

	/**
	 * Returns the char[] representation of the IASTBinaryExpression's operator.
	 */
	public static char[] getBinaryOperatorString(IASTBinaryExpression be) {
		switch (be.getOperator()) {
		case IASTBinaryExpression.op_multiply:
			return Keywords.cpSTAR;
		case IASTBinaryExpression.op_divide:
			return Keywords.cpDIV;
		case IASTBinaryExpression.op_modulo:
			return Keywords.cpMOD;
		case IASTBinaryExpression.op_plus:
			return Keywords.cpPLUS;
		case IASTBinaryExpression.op_minus:
			return Keywords.cpMINUS;
		case IASTBinaryExpression.op_shiftLeft:
			return Keywords.cpSHIFTL;
		case IASTBinaryExpression.op_shiftRight:
			return Keywords.cpSHIFTR;
		case IASTBinaryExpression.op_lessThan:
			return Keywords.cpLT;
		case IASTBinaryExpression.op_greaterThan:
			return Keywords.cpGT;
		case IASTBinaryExpression.op_lessEqual:
			return Keywords.cpLTEQUAL;
		case IASTBinaryExpression.op_greaterEqual:
			return Keywords.cpGTEQUAL;
		case IASTBinaryExpression.op_binaryAnd:
			return Keywords.cpAMPER;
		case IASTBinaryExpression.op_binaryXor:
			return Keywords.cpXOR;
		case IASTBinaryExpression.op_binaryOr:
			return Keywords.cpBITOR;
		case IASTBinaryExpression.op_logicalAnd:
			return Keywords.cpAND;
		case IASTBinaryExpression.op_logicalOr:
			return Keywords.cpOR;
		case IASTBinaryExpression.op_assign:
			return Keywords.cpASSIGN;
		case IASTBinaryExpression.op_multiplyAssign:
			return Keywords.cpSTARASSIGN;
		case IASTBinaryExpression.op_divideAssign:
			return Keywords.cpDIVASSIGN;
		case IASTBinaryExpression.op_moduloAssign:
			return Keywords.cpMODASSIGN;
		case IASTBinaryExpression.op_plusAssign:
			return Keywords.cpPLUSASSIGN;
		case IASTBinaryExpression.op_minusAssign:
			return Keywords.cpMINUSASSIGN;
		case IASTBinaryExpression.op_shiftLeftAssign:
			return Keywords.cpSHIFTLASSIGN;
		case IASTBinaryExpression.op_shiftRightAssign:
			return Keywords.cpSHIFTRASSIGN;
		case IASTBinaryExpression.op_binaryAndAssign:
			return Keywords.cpAMPERASSIGN;
		case IASTBinaryExpression.op_binaryXorAssign:
			return Keywords.cpXORASSIGN;
		case IASTBinaryExpression.op_binaryOrAssign:
			return Keywords.cpBITORASSIGN;
		case IASTBinaryExpression.op_equals:
			return Keywords.cpEQUAL;
		case IASTBinaryExpression.op_notequals:
			return Keywords.cpNOTEQUAL;
		case IASTBinaryExpression.op_max:
			return Keywords.cpMAX;
		case IASTBinaryExpression.op_min:
			return Keywords.cpMIN;
		case IASTBinaryExpression.op_pmarrow:
			return Keywords.cpARROW;
		case IASTBinaryExpression.op_pmdot:
			return Keywords.cpDOT;
		}

		return CharArrayUtils.EMPTY;
	}

	private static String getTypeIdExpressionOperator(IASTTypeIdExpression expression) {
		switch (expression.getOperator()) {
		case IASTTypeIdExpression.op_alignof:
			return Keywords.ALIGNOF;
		case IASTTypeIdExpression.op_typeof:
			return Keywords.TYPEOF;
		case ICPPASTTypeIdExpression.op_typeid:
			return Keywords.TYPEID;
		case IASTTypeIdExpression.op_sizeof:
			return Keywords.SIZEOF;
		}
		return ""; //$NON-NLS-1$
	}

	/**
	 * Returns the String representation of the pack expansion expression.
	 * @param buffer
	 */
	private static StringBuilder appendPackExpansionExpression(StringBuilder buffer,
			ICPPASTPackExpansionExpression expression) {
		appendExpressionString(buffer, expression.getPattern());
		return buffer.append(Keywords.cpELLIPSIS);
	}
}
