/***********************************************************************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others. All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors: IBM Corporation - initial API and implementation
 **********************************************************************************************************************************/
package net.sourceforge.phpdt.internal.compiler;

import net.sourceforge.phpdt.core.compiler.IProblem;
import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration;
import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit;
import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
import net.sourceforge.phpdt.internal.compiler.parser.UnitParser;
import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation;
import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;

/*
 * A document element parser extracts structural information from a piece of
 * source, providing detailed source positions info.
 * 
 * also see @IDocumentElementRequestor
 * 
 * The structural investigation includes: - the package statement - import
 * statements - top-level types: package member, member types (member types of
 * member types...) - fields - methods
 * 
 * Any (parsing) problem encountered is also provided.
 */
public class DocumentElementParser extends UnitParser {
	IDocumentElementRequestor requestor;

	private int localIntPtr;

	private int lastFieldEndPosition;

	private int lastFieldBodyEndPosition;

	private int typeStartPosition;

	private long selectorSourcePositions;

	private int typeDims;

	private int extendsDim;

	private int declarationSourceStart;

	/* int[] stack for storing javadoc positions */
	int[][] intArrayStack;

	int intArrayPtr;

	// CompilerOptions options;

	public DocumentElementParser(final IDocumentElementRequestor requestor,
			IProblemFactory problemFactory, CompilerOptions options) {
		super(new ProblemReporter(DefaultErrorHandlingPolicies
				.exitAfterAllProblems(), options, problemFactory) {
			public void record(IProblem problem, CompilationResult unitResult) {
				requestor.acceptProblem(problem);
			}
		});
		// false,
		// options.sourceLevel >= CompilerOptions.JDK1_4);
		this.requestor = requestor;
		intArrayStack = new int[30][];
		this.options = options;
	}

	/**
	 * 
	 * INTERNAL USE-ONLY
	 */
	// protected void adjustInterfaceModifiers() {
	// intStack[intPtr - 2] |= AccInterface;
	// }
	/*
	 * Will clear the comment stack when looking for a potential JavaDoc which
	 * might contain @deprecated.
	 * 
	 * Additionally, before investigating for @deprecated, retrieve the
	 * positions of the JavaDoc comments so as to notify requestor with them.
	 */
	// public void checkAnnotation() {
	//
	// /* persisting javadoc positions */
	// pushOnIntArrayStack(this.getJavaDocPositions());
	// boolean deprecated = false;
	// int lastAnnotationIndex = -1;
	// int commentPtr = scanner.commentPtr;
	//
	// //since jdk1.2 look only in the last java doc comment...
	// nextComment : for (lastAnnotationIndex = scanner.commentPtr;
	// lastAnnotationIndex >= 0; lastAnnotationIndex--){
	// //look for @deprecated into the first javadoc comment preceeding the
	// declaration
	// int commentSourceStart = scanner.commentStarts[lastAnnotationIndex];
	// // javadoc only (non javadoc comment have negative end positions.)
	// if (modifiersSourceStart != -1 && modifiersSourceStart <
	// commentSourceStart) {
	// continue nextComment;
	// }
	// if (scanner.commentStops[lastAnnotationIndex] < 0) {
	// continue nextComment;
	// }
	// int commentSourceEnd = scanner.commentStops[lastAnnotationIndex] - 1;
	// //stop is one over
	// char[] comment = scanner.source;
	//
	// deprecated =
	// checkDeprecation(
	// commentSourceStart,
	// commentSourceEnd,
	// comment);
	// break nextComment;
	// }
	// if (deprecated) {
	// checkAndSetModifiers(AccDeprecated);
	// }
	// // modify the modifier source start to point at the first comment
	// if (commentPtr >= 0) {
	// declarationSourceStart = scanner.commentStarts[0];
	// }
	// }
	/**
	 * 
	 * INTERNAL USE-ONLY
	 */
	// protected void consumeClassBodyDeclaration() {
	// // ClassBodyDeclaration ::= Diet Block
	// //push an Initializer
	// //optimize the push/pop
	//
	// super.consumeClassBodyDeclaration();
	// Initializer initializer = (Initializer) astStack[astPtr];
	// requestor.acceptInitializer(
	// initializer.declarationSourceStart,
	// initializer.declarationSourceEnd,
	// intArrayStack[intArrayPtr--],
	// 0,
	// modifiersSourceStart,
	// initializer.block.sourceStart,
	// initializer.block.sourceEnd);
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeClassDeclaration() {
	// super.consumeClassDeclaration();
	// // we know that we have a TypeDeclaration on the top of the astStack
	// if (isLocalDeclaration()) {
	// // we ignore the local variable declarations
	// return;
	// }
	// requestor.exitClass(endStatementPosition, // '}' is the end of the body
	// ((TypeDeclaration) astStack[astPtr]).declarationSourceEnd);
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeClassHeader() {
	// //ClassHeader ::= $empty
	// super.consumeClassHeader();
	// if (isLocalDeclaration()) {
	// // we ignore the local variable declarations
	// intArrayPtr--;
	// return;
	// }
	// TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr];
	// TypeReference[] superInterfaces = typeDecl.superInterfaces;
	// char[][] interfaceNames = null;
	// int[] interfaceNameStarts = null;
	// int[] interfaceNameEnds = null;
	// if (superInterfaces != null) {
	// int superInterfacesLength = superInterfaces.length;
	// interfaceNames = new char[superInterfacesLength][];
	// interfaceNameStarts = new int[superInterfacesLength];
	// interfaceNameEnds = new int[superInterfacesLength];
	// for (int i = 0; i < superInterfacesLength; i++) {
	// TypeReference superInterface = superInterfaces[i];
	// interfaceNames[i] =
	// CharOperation.concatWith(superInterface.getTypeName(), '.');
	// interfaceNameStarts[i] = superInterface.sourceStart;
	// interfaceNameEnds[i] = superInterface.sourceEnd;
	// }
	// }
	// // flush the comments related to the class header
	// scanner.commentPtr = -1;
	// TypeReference superclass = typeDecl.superclass;
	// if (superclass == null) {
	// requestor.enterClass(
	// typeDecl.declarationSourceStart,
	// intArrayStack[intArrayPtr--],
	// typeDecl.modifiers,
	// typeDecl.modifiersSourceStart,
	// typeStartPosition,
	// typeDecl.name,
	// typeDecl.sourceStart,
	// typeDecl.sourceEnd,
	// null,
	// -1,
	// -1,
	// interfaceNames,
	// interfaceNameStarts,
	// interfaceNameEnds,
	// scanner.currentPosition - 1);
	// } else {
	// requestor.enterClass(
	// typeDecl.declarationSourceStart,
	// intArrayStack[intArrayPtr--],
	// typeDecl.modifiers,
	// typeDecl.modifiersSourceStart,
	// typeStartPosition,
	// typeDecl.name,
	// typeDecl.sourceStart,
	// typeDecl.sourceEnd,
	// CharOperation.concatWith(superclass.getTypeName(), '.'),
	// superclass.sourceStart,
	// superclass.sourceEnd,
	// interfaceNames,
	// interfaceNameStarts,
	// interfaceNameEnds,
	// scanner.currentPosition - 1);
	//
	// }
	// }
	// protected void consumeClassHeaderName() {
	// // ClassHeaderName ::= Modifiersopt 'class' 'Identifier'
	// TypeDeclaration typeDecl;
	// if (nestedMethod[nestedType] == 0) {
	// if (nestedType != 0) {
	// typeDecl = new
	// MemberTypeDeclaration(this.compilationUnit.compilationResult);
	// } else {
	// typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
	// }
	// } else {
	// // Record that the block has a declaration for local types
	// typeDecl = new
	// LocalTypeDeclaration(this.compilationUnit.compilationResult);
	// markEnclosingMemberWithLocalType();
	// blockReal();
	// }
	//
	// //highlight the name of the type
	// long pos = identifierPositionStack[identifierPtr];
	// typeDecl.sourceEnd = (int) pos;
	// typeDecl.sourceStart = (int) (pos >>> 32);
	// typeDecl.name = identifierStack[identifierPtr--];
	// identifierLengthPtr--;
	//
	// //compute the declaration source too
	// // 'class' and 'interface' push an int position
	// typeStartPosition = typeDecl.declarationSourceStart = intStack[intPtr--];
	// intPtr--;
	// int declarationSourceStart = intStack[intPtr--];
	// typeDecl.modifiersSourceStart = intStack[intPtr--];
	// typeDecl.modifiers = intStack[intPtr--];
	// if (typeDecl.declarationSourceStart > declarationSourceStart) {
	// typeDecl.declarationSourceStart = declarationSourceStart;
	// }
	// typeDecl.bodyStart = typeDecl.sourceEnd + 1;
	// pushOnAstStack(typeDecl);
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeCompilationUnit() {
	// // CompilationUnit ::= EnterCompilationUnit PackageDeclarationopt
	// ImportDeclarationsopt
	// requestor.exitCompilationUnit(scanner.source.length - 1);
	// }
	/**
	 * 
	 * INTERNAL USE-ONLY
	 */
	// protected void consumeConstructorDeclaration() {
	// // ConstructorDeclaration ::= ConstructorHeader ConstructorBody
	// super.consumeConstructorDeclaration();
	// if (isLocalDeclaration()) {
	// // we ignore the local variable declarations
	// return;
	// }
	// ConstructorDeclaration cd = (ConstructorDeclaration) astStack[astPtr];
	// requestor.exitConstructor(endStatementPosition, cd.declarationSourceEnd);
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeConstructorHeader() {
	// // ConstructorHeader ::= ConstructorHeaderName MethodHeaderParameters
	// MethodHeaderThrowsClauseopt
	// super.consumeConstructorHeader();
	// if (isLocalDeclaration()) {
	// // we ignore the local variable declarations
	// intArrayPtr--;
	// return;
	// }
	// ConstructorDeclaration cd = (ConstructorDeclaration) astStack[astPtr];
	// Argument[] arguments = cd.arguments;
	// char[][] argumentTypes = null;
	// char[][] argumentNames = null;
	// int[] argumentTypeStarts = null;
	// int[] argumentTypeEnds = null;
	// int[] argumentNameStarts = null;
	// int[] argumentNameEnds = null;
	// if (arguments != null) {
	// int argumentLength = arguments.length;
	// argumentTypes = new char[argumentLength][];
	// argumentNames = new char[argumentLength][];
	// argumentNameStarts = new int[argumentLength];
	// argumentNameEnds = new int[argumentLength];
	// argumentTypeStarts = new int[argumentLength];
	// argumentTypeEnds = new int[argumentLength];
	// for (int i = 0; i < argumentLength; i++) {
	// Argument argument = arguments[i];
	// TypeReference argumentType = argument.type;
	// argumentTypes[i] = returnTypeName(argumentType);
	// argumentNames[i] = argument.name;
	// argumentNameStarts[i] = argument.sourceStart;
	// argumentNameEnds[i] = argument.sourceEnd;
	// argumentTypeStarts[i] = argumentType.sourceStart;
	// argumentTypeEnds[i] = argumentType.sourceEnd;
	// }
	// }
	// TypeReference[] thrownExceptions = cd.thrownExceptions;
	// char[][] exceptionTypes = null;
	// int[] exceptionTypeStarts = null;
	// int[] exceptionTypeEnds = null;
	// if (thrownExceptions != null) {
	// int thrownExceptionLength = thrownExceptions.length;
	// exceptionTypes = new char[thrownExceptionLength][];
	// exceptionTypeStarts = new int[thrownExceptionLength];
	// exceptionTypeEnds = new int[thrownExceptionLength];
	// for (int i = 0; i < thrownExceptionLength; i++) {
	// TypeReference exception = thrownExceptions[i];
	// exceptionTypes[i] = CharOperation.concatWith(exception.getTypeName(),
	// '.');
	// exceptionTypeStarts[i] = exception.sourceStart;
	// exceptionTypeEnds[i] = exception.sourceEnd;
	// }
	// }
	// requestor
	// .enterConstructor(
	// cd.declarationSourceStart,
	// intArrayStack[intArrayPtr--],
	// cd.modifiers,
	// cd.modifiersSourceStart,
	// cd.selector,
	// cd.sourceStart,
	// (int) (selectorSourcePositions & 0xFFFFFFFFL),
	// // retrieve the source end of the name
	// argumentTypes,
	// argumentTypeStarts,
	// argumentTypeEnds,
	// argumentNames,
	// argumentNameStarts,
	// argumentNameEnds,
	// rParenPos,
	// // right parenthesis
	// exceptionTypes,
	// exceptionTypeStarts,
	// exceptionTypeEnds,
	// scanner.currentPosition - 1);
	// }
	// protected void consumeConstructorHeaderName() {
	// // ConstructorHeaderName ::= Modifiersopt 'Identifier' '('
	// ConstructorDeclaration cd = new
	// ConstructorDeclaration(this.compilationUnit.compilationResult);
	//
	// //name -- this is not really revelant but we do .....
	// cd.selector = identifierStack[identifierPtr];
	// selectorSourcePositions = identifierPositionStack[identifierPtr--];
	// identifierLengthPtr--;
	//
	// //modifiers
	// cd.declarationSourceStart = intStack[intPtr--];
	// cd.modifiersSourceStart = intStack[intPtr--];
	// cd.modifiers = intStack[intPtr--];
	//
	// //highlight starts at the selector starts
	// cd.sourceStart = (int) (selectorSourcePositions >>> 32);
	// pushOnAstStack(cd);
	//
	// cd.sourceEnd = lParenPos;
	// cd.bodyStart = lParenPos + 1;
	// }
	// protected void consumeDefaultModifiers() {
	// checkAnnotation(); // might update modifiers with AccDeprecated
	// pushOnIntStack(modifiers); // modifiers
	// pushOnIntStack(-1);
	// pushOnIntStack(
	// declarationSourceStart >= 0 ? declarationSourceStart :
	// scanner.startPosition);
	// resetModifiers();
	// }
	// protected void consumeDiet() {
	// // Diet ::= $empty
	// super.consumeDiet();
	// /* persisting javadoc positions
	// * Will be consume in consumeClassBodyDeclaration
	// */
	// pushOnIntArrayStack(this.getJavaDocPositions());
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeEnterCompilationUnit() {
	// // EnterCompilationUnit ::= $empty
	// requestor.enterCompilationUnit();
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeEnterVariable() {
	// // EnterVariable ::= $empty
	// boolean isLocalDeclaration = isLocalDeclaration();
	// if (!isLocalDeclaration && (variablesCounter[nestedType] != 0)) {
	// requestor.exitField(lastFieldBodyEndPosition, lastFieldEndPosition);
	// }
	// char[] name = identifierStack[identifierPtr];
	// long namePosition = identifierPositionStack[identifierPtr--];
	// int extendedTypeDimension = intStack[intPtr--];
	//
	// AbstractVariableDeclaration declaration;
	// if (nestedMethod[nestedType] != 0) {
	// // create the local variable declarations
	// declaration =
	// new LocalDeclaration(null, name, (int) (namePosition >>> 32), (int)
	// namePosition);
	// } else {
	// // create the field declaration
	// declaration =
	// new FieldDeclaration(null, name, (int) (namePosition >>> 32), (int)
	// namePosition);
	// }
	// identifierLengthPtr--;
	// TypeReference type;
	// int variableIndex = variablesCounter[nestedType];
	// int typeDim = 0;
	// if (variableIndex == 0) {
	// // first variable of the declaration (FieldDeclaration or
	// LocalDeclaration)
	// if (nestedMethod[nestedType] != 0) {
	// // local declaration
	// declaration.declarationSourceStart = intStack[intPtr--];
	// declaration.modifiersSourceStart = intStack[intPtr--];
	// declaration.modifiers = intStack[intPtr--];
	// type = getTypeReference(typeDim = intStack[intPtr--]); // type dimension
	// pushOnAstStack(type);
	// } else {
	// // field declaration
	// type = getTypeReference(typeDim = intStack[intPtr--]); // type dimension
	// pushOnAstStack(type);
	// declaration.declarationSourceStart = intStack[intPtr--];
	// declaration.modifiersSourceStart = intStack[intPtr--];
	// declaration.modifiers = intStack[intPtr--];
	// }
	// } else {
	// type = (TypeReference) astStack[astPtr - variableIndex];
	// typeDim = type.dimensions();
	// AbstractVariableDeclaration previousVariable =
	// (AbstractVariableDeclaration) astStack[astPtr];
	// declaration.declarationSourceStart =
	// previousVariable.declarationSourceStart;
	// declaration.modifiers = previousVariable.modifiers;
	// declaration.modifiersSourceStart = previousVariable.modifiersSourceStart;
	// }
	//
	// localIntPtr = intPtr;
	//
	// if (extendedTypeDimension == 0) {
	// declaration.type = type;
	// } else {
	// int dimension = typeDim + extendedTypeDimension;
	// //on the identifierLengthStack there is the information about the
	// type....
	// int baseType;
	// if ((baseType = identifierLengthStack[identifierLengthPtr + 1]) < 0) {
	// //it was a baseType
	// declaration.type = TypeReference.baseTypeReference(-baseType, dimension);
	// declaration.type.sourceStart = type.sourceStart;
	// declaration.type.sourceEnd = type.sourceEnd;
	// } else {
	// declaration.type = this.copyDims(type, dimension);
	// }
	// }
	// variablesCounter[nestedType]++;
	// nestedMethod[nestedType]++;
	// pushOnAstStack(declaration);
	//
	// int[] javadocPositions = intArrayStack[intArrayPtr];
	// if (!isLocalDeclaration) {
	// requestor
	// .enterField(
	// declaration.declarationSourceStart,
	// javadocPositions,
	// declaration.modifiers,
	// declaration.modifiersSourceStart,
	// returnTypeName(declaration.type),
	// type.sourceStart,
	// type.sourceEnd,
	// typeDims,
	// name,
	// (int) (namePosition >>> 32),
	// (int) namePosition,
	// extendedTypeDimension,
	// extendedTypeDimension == 0 ? -1 : endPosition);
	// }
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeExitVariableWithInitialization() {
	// // ExitVariableWithInitialization ::= $empty
	// // the scanner is located after the comma or the semi-colon.
	// // we want to include the comma or the semi-colon
	// super.consumeExitVariableWithInitialization();
	// nestedMethod[nestedType]--;
	// lastFieldEndPosition = scanner.currentPosition - 1;
	// lastFieldBodyEndPosition = ((AbstractVariableDeclaration)
	// astStack[astPtr]).initialization.sourceEnd;
	// }
	// protected void consumeExitVariableWithoutInitialization() {
	// // ExitVariableWithoutInitialization ::= $empty
	// // do nothing by default
	// super.consumeExitVariableWithoutInitialization();
	// nestedMethod[nestedType]--;
	// lastFieldEndPosition = scanner.currentPosition - 1;
	// lastFieldBodyEndPosition = scanner.startPosition - 1;
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeFieldDeclaration() {
	// // See consumeLocalVariableDeclarationDefaultModifier() in case of
	// change: duplicated code
	// // FieldDeclaration ::= Modifiersopt Type VariableDeclarators ';'
	// // the super.consumeFieldDeclaration will reinitialize the
	// variableCounter[nestedType]
	// int variableIndex = variablesCounter[nestedType];
	// super.consumeFieldDeclaration();
	// intArrayPtr--;
	// if (isLocalDeclaration())
	// return;
	// if (variableIndex != 0) {
	// requestor.exitField(lastFieldBodyEndPosition, lastFieldEndPosition);
	// }
	// }
	// protected void consumeFormalParameter() {
	// // FormalParameter ::= Type VariableDeclaratorId ==> false
	// // FormalParameter ::= Modifiers Type VariableDeclaratorId ==> true
	// /*
	// astStack :
	// identifierStack : type identifier
	// intStack : dim dim
	// ==>
	// astStack : Argument
	// identifierStack :
	// intStack :
	// */
	//
	// identifierLengthPtr--;
	// char[] name = identifierStack[identifierPtr];
	// long namePositions = identifierPositionStack[identifierPtr--];
	// TypeReference type = getTypeReference(intStack[intPtr--] +
	// intStack[intPtr--]);
	// intPtr -= 3;
	// Argument arg =
	// new Argument(
	// name,
	// namePositions,
	// type,
	// intStack[intPtr + 1]); // modifiers
	// pushOnAstStack(arg);
	// intArrayPtr--;
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeInterfaceDeclaration() {
	// super.consumeInterfaceDeclaration();
	// // we know that we have a TypeDeclaration on the top of the astStack
	// if (isLocalDeclaration()) {
	// // we ignore the local variable declarations
	// return;
	// }
	// requestor.exitInterface(endStatementPosition, // the '}' is the end of
	// the body
	// ((TypeDeclaration) astStack[astPtr]).declarationSourceEnd);
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeInterfaceHeader() {
	// //InterfaceHeader ::= $empty
	// super.consumeInterfaceHeader();
	// if (isLocalDeclaration()) {
	// // we ignore the local variable declarations
	// intArrayPtr--;
	// return;
	// }
	// TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr];
	// TypeReference[] superInterfaces = typeDecl.superInterfaces;
	// char[][] interfaceNames = null;
	// int[] interfaceNameStarts = null;
	// int[] interfacenameEnds = null;
	// int superInterfacesLength = 0;
	// if (superInterfaces != null) {
	// superInterfacesLength = superInterfaces.length;
	// interfaceNames = new char[superInterfacesLength][];
	// interfaceNameStarts = new int[superInterfacesLength];
	// interfacenameEnds = new int[superInterfacesLength];
	// }
	// if (superInterfaces != null) {
	// for (int i = 0; i < superInterfacesLength; i++) {
	// TypeReference superInterface = superInterfaces[i];
	// interfaceNames[i] =
	// CharOperation.concatWith(superInterface.getTypeName(), '.');
	// interfaceNameStarts[i] = superInterface.sourceStart;
	// interfacenameEnds[i] = superInterface.sourceEnd;
	// }
	// }
	// // flush the comments related to the interface header
	// scanner.commentPtr = -1;
	// requestor.enterInterface(
	// typeDecl.declarationSourceStart,
	// intArrayStack[intArrayPtr--],
	// typeDecl.modifiers,
	// typeDecl.modifiersSourceStart,
	// typeStartPosition,
	// typeDecl.name,
	// typeDecl.sourceStart,
	// typeDecl.sourceEnd,
	// interfaceNames,
	// interfaceNameStarts,
	// interfacenameEnds,
	// scanner.currentPosition - 1);
	// }
	// protected void consumeInterfaceHeaderName() {
	// // InterfaceHeaderName ::= Modifiersopt 'interface' 'Identifier'
	// TypeDeclaration typeDecl;
	// if (nestedMethod[nestedType] == 0) {
	// if (nestedType != 0) {
	// typeDecl = new
	// MemberTypeDeclaration(this.compilationUnit.compilationResult);
	// } else {
	// typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
	// }
	// } else {
	// // Record that the block has a declaration for local types
	// typeDecl = new
	// LocalTypeDeclaration(this.compilationUnit.compilationResult);
	// markEnclosingMemberWithLocalType();
	// blockReal();
	// }
	//
	// //highlight the name of the type
	// long pos = identifierPositionStack[identifierPtr];
	// typeDecl.sourceEnd = (int) pos;
	// typeDecl.sourceStart = (int) (pos >>> 32);
	// typeDecl.name = identifierStack[identifierPtr--];
	// identifierLengthPtr--;
	//
	// //compute the declaration source too
	// // 'class' and 'interface' push an int position
	// typeStartPosition = typeDecl.declarationSourceStart = intStack[intPtr--];
	// intPtr--;
	// int declarationSourceStart = intStack[intPtr--];
	// typeDecl.modifiersSourceStart = intStack[intPtr--];
	// typeDecl.modifiers = intStack[intPtr--];
	// if (typeDecl.declarationSourceStart > declarationSourceStart) {
	// typeDecl.declarationSourceStart = declarationSourceStart;
	// }
	// typeDecl.bodyStart = typeDecl.sourceEnd + 1;
	// pushOnAstStack(typeDecl);
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeLocalVariableDeclaration() {
	// // See consumeLocalVariableDeclarationDefaultModifier() in case of
	// change: duplicated code
	// // FieldDeclaration ::= Modifiersopt Type VariableDeclarators ';'
	//
	// super.consumeLocalVariableDeclaration();
	// intArrayPtr--;
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeMethodDeclaration(boolean isNotAbstract) {
	// // MethodDeclaration ::= MethodHeader MethodBody
	// // AbstractMethodDeclaration ::= MethodHeader ';'
	// super.consumeMethodDeclaration(isNotAbstract);
	// if (isLocalDeclaration()) {
	// // we ignore the local variable declarations
	// return;
	// }
	// MethodDeclaration md = (MethodDeclaration) astStack[astPtr];
	// requestor.exitMethod(endStatementPosition, md.declarationSourceEnd);
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeMethodHeader() {
	// // MethodHeader ::= MethodHeaderName MethodHeaderParameters
	// MethodHeaderExtendedDims ThrowsClauseopt
	// super.consumeMethodHeader();
	// if (isLocalDeclaration()) {
	// // we ignore the local variable declarations
	// intArrayPtr--;
	// return;
	// }
	// MethodDeclaration md = (MethodDeclaration) astStack[astPtr];
	//
	// TypeReference returnType = md.returnType;
	// char[] returnTypeName = returnTypeName(returnType);
	// Argument[] arguments = md.arguments;
	// char[][] argumentTypes = null;
	// char[][] argumentNames = null;
	// int[] argumentTypeStarts = null;
	// int[] argumentTypeEnds = null;
	// int[] argumentNameStarts = null;
	// int[] argumentNameEnds = null;
	// if (arguments != null) {
	// int argumentLength = arguments.length;
	// argumentTypes = new char[argumentLength][];
	// argumentNames = new char[argumentLength][];
	// argumentNameStarts = new int[argumentLength];
	// argumentNameEnds = new int[argumentLength];
	// argumentTypeStarts = new int[argumentLength];
	// argumentTypeEnds = new int[argumentLength];
	// for (int i = 0; i < argumentLength; i++) {
	// Argument argument = arguments[i];
	// TypeReference argumentType = argument.type;
	// argumentTypes[i] = returnTypeName(argumentType);
	// argumentNames[i] = argument.name;
	// argumentNameStarts[i] = argument.sourceStart;
	// argumentNameEnds[i] = argument.sourceEnd;
	// argumentTypeStarts[i] = argumentType.sourceStart;
	// argumentTypeEnds[i] = argumentType.sourceEnd;
	// }
	// }
	// TypeReference[] thrownExceptions = md.thrownExceptions;
	// char[][] exceptionTypes = null;
	// int[] exceptionTypeStarts = null;
	// int[] exceptionTypeEnds = null;
	// if (thrownExceptions != null) {
	// int thrownExceptionLength = thrownExceptions.length;
	// exceptionTypeStarts = new int[thrownExceptionLength];
	// exceptionTypeEnds = new int[thrownExceptionLength];
	// exceptionTypes = new char[thrownExceptionLength][];
	// for (int i = 0; i < thrownExceptionLength; i++) {
	// TypeReference exception = thrownExceptions[i];
	// exceptionTypes[i] = CharOperation.concatWith(exception.getTypeName(),
	// '.');
	// exceptionTypeStarts[i] = exception.sourceStart;
	// exceptionTypeEnds[i] = exception.sourceEnd;
	// }
	// }
	// requestor
	// .enterMethod(
	// md.declarationSourceStart,
	// intArrayStack[intArrayPtr--],
	// md.modifiers,
	// md.modifiersSourceStart,
	// returnTypeName,
	// returnType.sourceStart,
	// returnType.sourceEnd,
	// typeDims,
	// md.selector,
	// md.sourceStart,
	// (int) (selectorSourcePositions & 0xFFFFFFFFL),
	// argumentTypes,
	// argumentTypeStarts,
	// argumentTypeEnds,
	// argumentNames,
	// argumentNameStarts,
	// argumentNameEnds,
	// rParenPos,
	// extendsDim,
	// extendsDim == 0 ? -1 : endPosition,
	// exceptionTypes,
	// exceptionTypeStarts,
	// exceptionTypeEnds,
	// scanner.currentPosition - 1);
	// }
	// protected void consumeMethodHeaderExtendedDims() {
	// // MethodHeaderExtendedDims ::= Dimsopt
	// // now we update the returnType of the method
	// MethodDeclaration md = (MethodDeclaration) astStack[astPtr];
	// int extendedDims = intStack[intPtr--];
	// extendsDim = extendedDims;
	// if (extendedDims != 0) {
	// TypeReference returnType = md.returnType;
	// md.sourceEnd = endPosition;
	// int dims = returnType.dimensions() + extendedDims;
	// int baseType;
	// if ((baseType = identifierLengthStack[identifierLengthPtr + 1]) < 0) {
	// //it was a baseType
	// int sourceStart = returnType.sourceStart;
	// int sourceEnd = returnType.sourceEnd;
	// returnType = TypeReference.baseTypeReference(-baseType, dims);
	// returnType.sourceStart = sourceStart;
	// returnType.sourceEnd = sourceEnd;
	// md.returnType = returnType;
	// } else {
	// md.returnType = this.copyDims(md.returnType, dims);
	// }
	// if (currentToken == TokenNameLBRACE) {
	// md.bodyStart = endPosition + 1;
	// }
	// }
	// }
	// protected void consumeMethodHeaderName() {
	// // MethodHeaderName ::= Modifiersopt Type 'Identifier' '('
	// MethodDeclaration md = new
	// MethodDeclaration(this.compilationUnit.compilationResult);
	//
	// //name
	// md.selector = identifierStack[identifierPtr];
	// selectorSourcePositions = identifierPositionStack[identifierPtr--];
	// identifierLengthPtr--;
	// //type
	// md.returnType = getTypeReference(typeDims = intStack[intPtr--]);
	// //modifiers
	// md.declarationSourceStart = intStack[intPtr--];
	// md.modifiersSourceStart = intStack[intPtr--];
	// md.modifiers = intStack[intPtr--];
	//
	// //highlight starts at selector start
	// md.sourceStart = (int) (selectorSourcePositions >>> 32);
	// pushOnAstStack(md);
	// md.bodyStart = scanner.currentPosition-1;
	// }
	// protected void consumeModifiers() {
	// checkAnnotation(); // might update modifiers with AccDeprecated
	// pushOnIntStack(modifiers); // modifiers
	// pushOnIntStack(modifiersSourceStart);
	// pushOnIntStack(
	// declarationSourceStart >= 0 ? declarationSourceStart :
	// modifiersSourceStart);
	// resetModifiers();
	// }
	/**
	 * 
	 * INTERNAL USE-ONLY
	 */
	// protected void consumePackageDeclarationName() {
	// /* persisting javadoc positions */
	// pushOnIntArrayStack(this.getJavaDocPositions());
	//
	// super.consumePackageDeclarationName();
	// ImportReference importReference = compilationUnit.currentPackage;
	//
	// requestor.acceptPackage(
	// importReference.declarationSourceStart,
	// importReference.declarationSourceEnd,
	// intArrayStack[intArrayPtr--],
	// CharOperation.concatWith(importReference.getImportName(), '.'),
	// importReference.sourceStart);
	// }
	// protected void consumePushModifiers() {
	// checkAnnotation(); // might update modifiers with AccDeprecated
	// pushOnIntStack(modifiers); // modifiers
	// if (modifiersSourceStart < 0) {
	// pushOnIntStack(-1);
	// pushOnIntStack(
	// declarationSourceStart >= 0 ? declarationSourceStart :
	// scanner.startPosition);
	// } else {
	// pushOnIntStack(modifiersSourceStart);
	// pushOnIntStack(
	// declarationSourceStart >= 0 ? declarationSourceStart :
	// modifiersSourceStart);
	// }
	// resetModifiers();
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeSingleTypeImportDeclarationName() {
	// // SingleTypeImportDeclarationName ::= 'import' Name
	//
	// /* persisting javadoc positions */
	// pushOnIntArrayStack(this.getJavaDocPositions());
	//
	// super.consumeSingleTypeImportDeclarationName();
	// ImportReference importReference = (ImportReference) astStack[astPtr];
	// requestor.acceptImport(
	// importReference.declarationSourceStart,
	// importReference.declarationSourceEnd,
	// intArrayStack[intArrayPtr--],
	// CharOperation.concatWith(importReference.getImportName(), '.'),
	// importReference.sourceStart,
	// false);
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeStaticInitializer() {
	// // StaticInitializer ::= StaticOnly Block
	// //push an Initializer
	// //optimize the push/pop
	// super.consumeStaticInitializer();
	// Initializer initializer = (Initializer) astStack[astPtr];
	// requestor.acceptInitializer(
	// initializer.declarationSourceStart,
	// initializer.declarationSourceEnd,
	// intArrayStack[intArrayPtr--],
	// AccStatic,
	// intStack[intPtr--],
	// initializer.block.sourceStart,
	// initializer.declarationSourceEnd);
	// }
	// protected void consumeStaticOnly() {
	// // StaticOnly ::= 'static'
	// checkAnnotation(); // might update declaration source start
	// pushOnIntStack(modifiersSourceStart);
	// pushOnIntStack(
	// declarationSourceStart >= 0 ? declarationSourceStart :
	// modifiersSourceStart);
	// jumpOverMethodBody();
	// nestedMethod[nestedType]++;
	// resetModifiers();
	// }
	// /**
	// *
	// * INTERNAL USE-ONLY
	// */
	// protected void consumeTypeImportOnDemandDeclarationName() {
	// // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*'
	//
	// /* persisting javadoc positions */
	// pushOnIntArrayStack(this.getJavaDocPositions());
	//
	// super.consumeTypeImportOnDemandDeclarationName();
	// ImportReference importReference = (ImportReference) astStack[astPtr];
	// requestor.acceptImport(
	// importReference.declarationSourceStart,
	// importReference.declarationSourceEnd,
	// intArrayStack[intArrayPtr--],
	// CharOperation.concatWith(importReference.getImportName(), '.'),
	// importReference.sourceStart,
	// true);
	// }
	public CompilationUnitDeclaration endParse(int act) {
		if (scanner.recordLineSeparator) {
			requestor.acceptLineSeparatorPositions(scanner.getLineEnds());
		}
		return super.endParse(act);
	}

	/*
	 * Flush annotations defined prior to a given positions.
	 * 
	 * Note: annotations are stacked in syntactical order
	 * 
	 * Either answer given <position>, or the end position of a comment line
	 * immediately following the <position> (same line)
	 * 
	 * e.g. void foo(){ } // end of method foo
	 */

	// public int flushAnnotationsDefinedPriorTo(int position) {
	//
	// return lastFieldEndPosition =
	// super.flushAnnotationsDefinedPriorTo(position);
	// }
	// protected TypeReference getTypeReference(int dim) { /* build a Reference
	// on a variable that may be qualified or not
	// This variable is a type reference and dim will be its dimensions*/
	//
	// int length;
	// TypeReference ref;
	// if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
	// // single variable reference
	// if (dim == 0) {
	// ref =
	// new SingleTypeReference(
	// identifierStack[identifierPtr],
	// identifierPositionStack[identifierPtr--]);
	// } else {
	// ref =
	// new ArrayTypeReference(
	// identifierStack[identifierPtr],
	// dim,
	// identifierPositionStack[identifierPtr--]);
	// ref.sourceEnd = endPosition;
	// }
	// } else {
	// if (length < 0) { //flag for precompiled type reference on base types
	// ref = TypeReference.baseTypeReference(-length, dim);
	// ref.sourceStart = intStack[intPtr--];
	// if (dim == 0) {
	// ref.sourceEnd = intStack[intPtr--];
	// } else {
	// intPtr--;
	// ref.sourceEnd = endPosition;
	// }
	// } else { //Qualified variable reference
	// char[][] tokens = new char[length][];
	// identifierPtr -= length;
	// long[] positions = new long[length];
	// System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
	// System.arraycopy(
	// identifierPositionStack,
	// identifierPtr + 1,
	// positions,
	// 0,
	// length);
	// if (dim == 0) {
	// ref = new QualifiedTypeReference(tokens, positions);
	// } else {
	// ref = new ArrayQualifiedTypeReference(tokens, dim, positions);
	// ref.sourceEnd = endPosition;
	// }
	// }
	// };
	// return ref;
	// }
	public void initialize() {
		// positionning the parser for a new compilation unit
		// avoiding stack reallocation and all that....
		super.initialize(false);
		intArrayPtr = -1;
	}

	/**
	 * 
	 * INTERNAL USE-ONLY
	 */
	// private boolean isLocalDeclaration() {
	// int nestedDepth = nestedType;
	// while (nestedDepth >= 0) {
	// if (nestedMethod[nestedDepth] != 0) {
	// return true;
	// }
	// nestedDepth--;
	// }
	// return false;
	// }
	/*
	 * Investigate one entire unit.
	 */
	public void parseCompilationUnit(ICompilationUnit unit) {
		char[] regionSource = unit.getContents();
		try {
			initialize();
			goForCompilationUnit();
			referenceContext = compilationUnit = new CompilationUnitDeclaration(
					problemReporter(), new CompilationResult(unit, 0, 0, 10), // this.options.maxProblemsPerUnit),
					regionSource.length);
			scanner.resetTo(0, regionSource.length);
			scanner.setSource(regionSource);
			parse();
		} catch (AbortCompilation ex) {
		}
	}

	/*
	 * Investigate one constructor declaration.
	 */
	// public void parseConstructor(char[] regionSource) {
	// try {
	// initialize();
	// goForClassBodyDeclarations();
	// referenceContext =
	// compilationUnit =
	// compilationUnit =
	// new CompilationUnitDeclaration(
	// problemReporter(),
	// new CompilationResult(regionSource, 0, 0, 10),
	// //this.options.maxProblemsPerUnit),
	// regionSource.length);
	// scanner.resetTo(0, regionSource.length);
	// scanner.setSource(regionSource);
	// parse();
	// } catch (AbortCompilation ex) {
	// }
	// }
	/*
	 * Investigate one field declaration statement (might have multiple
	 * declarations in it).
	 */
	// public void parseField(char[] regionSource) {
	// try {
	// initialize();
	// goForFieldDeclaration();
	// referenceContext =
	// compilationUnit =
	// compilationUnit =
	// new CompilationUnitDeclaration(
	// problemReporter(),
	// new CompilationResult(regionSource, 0, 0,
	// this.options.maxProblemsPerUnit),
	// regionSource.length);
	// scanner.resetTo(0, regionSource.length);
	// scanner.setSource(regionSource);
	// parse();
	// } catch (AbortCompilation ex) {
	// }
	//
	// }
	// /*
	// * Investigate one import statement declaration.
	// */
	// public void parseImport(char[] regionSource) {
	// try {
	// initialize();
	// goForImportDeclaration();
	// referenceContext =
	// compilationUnit =
	// compilationUnit =
	// new CompilationUnitDeclaration(
	// problemReporter(),
	// new CompilationResult(regionSource, 0, 0,
	// this.options.maxProblemsPerUnit),
	// regionSource.length);
	// scanner.resetTo(0, regionSource.length);
	// scanner.setSource(regionSource);
	// parse();
	// } catch (AbortCompilation ex) {
	// }
	//
	// }
	// /*
	// * Investigate one initializer declaration.
	// * regionSource need to content exactly an initializer declaration.
	// * e.g: static { i = 4; }
	// * { name = "test"; }
	// */
	// public void parseInitializer(char[] regionSource) {
	// try {
	// initialize();
	// goForInitializer();
	// referenceContext =
	// compilationUnit =
	// compilationUnit =
	// new CompilationUnitDeclaration(
	// problemReporter(),
	// new CompilationResult(regionSource, 0, 0,
	// this.options.maxProblemsPerUnit),
	// regionSource.length);
	// scanner.resetTo(0, regionSource.length);
	// scanner.setSource(regionSource);
	// parse();
	// } catch (AbortCompilation ex) {
	// }
	//
	// }
	// /*
	// * Investigate one method declaration.
	// */
	// public void parseMethod(char[] regionSource) {
	// try {
	// initialize();
	// goForGenericMethodDeclaration();
	// referenceContext =
	// compilationUnit =
	// compilationUnit =
	// new CompilationUnitDeclaration(
	// problemReporter(),
	// new CompilationResult(regionSource, 0, 0,
	// this.options.maxProblemsPerUnit),
	// regionSource.length);
	// scanner.resetTo(0, regionSource.length);
	// scanner.setSource(regionSource);
	// parse();
	// } catch (AbortCompilation ex) {
	// }
	//
	// }
	// /*
	// * Investigate one package statement declaration.
	// */
	// public void parsePackage(char[] regionSource) {
	// try {
	// initialize();
	// goForPackageDeclaration();
	// referenceContext =
	// compilationUnit =
	// compilationUnit =
	// new CompilationUnitDeclaration(
	// problemReporter(),
	// new CompilationResult(regionSource, 0, 0,
	// this.options.maxProblemsPerUnit),
	// regionSource.length);
	// scanner.resetTo(0, regionSource.length);
	// scanner.setSource(regionSource);
	// parse();
	// } catch (AbortCompilation ex) {
	// }
	//
	// }
	// /*
	// * Investigate one type declaration, its fields, methods and member types.
	// */
	// public void parseType(char[] regionSource) {
	// try {
	// initialize();
	// goForTypeDeclaration();
	// referenceContext =
	// compilationUnit =
	// compilationUnit =
	// new CompilationUnitDeclaration(
	// problemReporter(),
	// new CompilationResult(regionSource, 0, 0,
	// this.options.maxProblemsPerUnit),
	// regionSource.length);
	// scanner.resetTo(0, regionSource.length);
	// scanner.setSource(regionSource);
	// parse();
	// } catch (AbortCompilation ex) {
	// }
	//
	// }
	/**
	 * Returns this parser's problem reporter initialized with its reference
	 * context. Also it is assumed that a problem is going to be reported, so
	 * initializes the compilation result's line positions.
	 */
	public ProblemReporter problemReporter() {
		problemReporter.referenceContext = referenceContext;
		return problemReporter;
	}

	protected void pushOnIntArrayStack(int[] positions) {

		try {
			intArrayStack[++intArrayPtr] = positions;
		} catch (IndexOutOfBoundsException e) {
			// intPtr is correct
			int oldStackLength = intArrayStack.length;
			int oldStack[][] = intArrayStack;
			intArrayStack = new int[oldStackLength + StackIncrement][];
			System.arraycopy(oldStack, 0, intArrayStack, 0, oldStackLength);
			intArrayStack[intArrayPtr] = positions;
		}
	}

	// protected void resetModifiers() {
	// super.resetModifiers();
	// declarationSourceStart = -1;
	// }
	/*
	 * Syntax error was detected. Will attempt to perform some recovery action
	 * in order to resume to the regular parse loop.
	 */
	protected boolean resumeOnSyntaxError() {
		return false;
	}
	/*
	 * Answer a char array representation of the type name formatted like: -
	 * type name + dimensions Example: "A[][]".toCharArray()
	 * "java.lang.String".toCharArray()
	 */
	// private char[] returnTypeName(TypeReference type) {
	// int dimension = type.dimensions();
	// if (dimension != 0) {
	// char[] dimensionsArray = new char[dimension * 2];
	// for (int i = 0; i < dimension; i++) {
	// dimensionsArray[i*2] = '[';
	// dimensionsArray[(i*2) + 1] = ']';
	// }
	// return CharOperation.concat(
	// CharOperation.concatWith(type.getTypeName(), '.'),
	// dimensionsArray);
	// }
	// return CharOperation.concatWith(type.getTypeName(), '.');
	// }
	// public String toString() {
	// StringBuffer buffer = new StringBuffer();
	// buffer.append("intArrayPtr = " + intArrayPtr + "\n"); //$NON-NLS-1$
	// //$NON-NLS-2$
	// buffer.append(super.toString());
	// return buffer.toString();
	// }
	// /**
	// * INTERNAL USE ONLY
	// */
	// protected TypeReference typeReference(
	// int dim,
	// int localIdentifierPtr,
	// int localIdentifierLengthPtr) {
	// /* build a Reference on a variable that may be qualified or not
	// * This variable is a type reference and dim will be its dimensions.
	// * We don't have any side effect on the stacks' pointers.
	// */
	//
	// int length;
	// TypeReference ref;
	// if ((length = identifierLengthStack[localIdentifierLengthPtr]) == 1) {
	// // single variable reference
	// if (dim == 0) {
	// ref =
	// new SingleTypeReference(
	// identifierStack[localIdentifierPtr],
	// identifierPositionStack[localIdentifierPtr--]);
	// } else {
	// ref =
	// new ArrayTypeReference(
	// identifierStack[localIdentifierPtr],
	// dim,
	// identifierPositionStack[localIdentifierPtr--]);
	// ref.sourceEnd = endPosition;
	// }
	// } else {
	// if (length < 0) { //flag for precompiled type reference on base types
	// ref = TypeReference.baseTypeReference(-length, dim);
	// ref.sourceStart = intStack[localIntPtr--];
	// if (dim == 0) {
	// ref.sourceEnd = intStack[localIntPtr--];
	// } else {
	// localIntPtr--;
	// ref.sourceEnd = endPosition;
	// }
	// } else { //Qualified variable reference
	// char[][] tokens = new char[length][];
	// localIdentifierPtr -= length;
	// long[] positions = new long[length];
	// System.arraycopy(identifierStack, localIdentifierPtr + 1, tokens, 0,
	// length);
	// System.arraycopy(
	// identifierPositionStack,
	// localIdentifierPtr + 1,
	// positions,
	// 0,
	// length);
	// if (dim == 0)
	// ref = new QualifiedTypeReference(tokens, positions);
	// else
	// ref = new ArrayQualifiedTypeReference(tokens, dim, positions);
	// }
	// };
	// return ref;
	// }
}