/*******************************************************************************
 * Copyright (c) 2006, 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:
 *     Anton Leherbauer (Wind River Systems) - initial API and implementation
 *     Markus Schorn (Wind River Systems)
 *     Sergey Prigogin (Google)
 *******************************************************************************/
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.ICPPASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
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.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(' ');
					}
					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) {
			//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) {
				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_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());
		}
		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);
	}
}
