/******************************************************************************* | |
* Copyright (c) 2000, 2004 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 org.eclipse.wst.jsdt.internal.compiler.parser; | |
/** | |
* Internal field structure for parsing recovery | |
*/ | |
import org.eclipse.wst.jsdt.internal.compiler.ast.AbstractMethodDeclaration; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.ASTNode; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.Block; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.CompilationUnitDeclaration; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.FieldDeclaration; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.ImportReference; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.Initializer; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.TypeDeclaration; | |
public class RecoveredUnit extends RecoveredElement { | |
public CompilationUnitDeclaration unitDeclaration; | |
public RecoveredImport[] imports; | |
public int importCount; | |
public RecoveredType[] types; | |
public int typeCount; | |
public RecoveredUnit(CompilationUnitDeclaration unitDeclaration, int bracketBalance, Parser parser){ | |
super(null, bracketBalance, parser); | |
this.unitDeclaration = unitDeclaration; | |
} | |
/* | |
* Record a method declaration: should be attached to last type | |
*/ | |
public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalanceValue) { | |
/* attach it to last type - if any */ | |
if (this.typeCount > 0){ | |
RecoveredType type = this.types[this.typeCount -1]; | |
int start = type.bodyEnd; | |
int end = type.typeDeclaration.bodyEnd; | |
type.bodyEnd = 0; // reset position | |
type.typeDeclaration.declarationSourceEnd = 0; // reset position | |
type.typeDeclaration.bodyEnd = 0; | |
if(start < end) { | |
Initializer initializer = new Initializer(new Block(0), 0); | |
initializer.bodyStart = end; | |
initializer.bodyEnd = end; | |
initializer.declarationSourceStart = end; | |
initializer.declarationSourceEnd = start; | |
type.add(initializer, bracketBalanceValue); | |
} | |
return type.add(methodDeclaration, bracketBalanceValue); | |
} | |
return this; // ignore | |
} | |
/* | |
* Record a field declaration: should be attached to last type | |
*/ | |
public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) { | |
/* attach it to last type - if any */ | |
if (this.typeCount > 0){ | |
RecoveredType type = this.types[this.typeCount -1]; | |
type.bodyEnd = 0; // reset position | |
type.typeDeclaration.declarationSourceEnd = 0; // reset position | |
type.typeDeclaration.bodyEnd = 0; | |
return type.add(fieldDeclaration, bracketBalanceValue); | |
} | |
return this; // ignore | |
} | |
public RecoveredElement add(ImportReference importReference, int bracketBalanceValue) { | |
if (this.imports == null) { | |
this.imports = new RecoveredImport[5]; | |
this.importCount = 0; | |
} else { | |
if (this.importCount == this.imports.length) { | |
System.arraycopy( | |
this.imports, | |
0, | |
(this.imports = new RecoveredImport[2 * this.importCount]), | |
0, | |
this.importCount); | |
} | |
} | |
RecoveredImport element = new RecoveredImport(importReference, this, bracketBalanceValue); | |
this.imports[this.importCount++] = element; | |
/* if import not finished, then import becomes current */ | |
if (importReference.declarationSourceEnd == 0) return element; | |
return this; | |
} | |
public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) { | |
if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0){ | |
if (this.typeCount > 0) { | |
// add it to the last type | |
RecoveredType lastType = this.types[this.typeCount-1]; | |
lastType.bodyEnd = 0; // reopen type | |
lastType.typeDeclaration.bodyEnd = 0; // reopen type | |
lastType.typeDeclaration.declarationSourceEnd = 0; // reopen type | |
lastType.bracketBalance++; // expect one closing brace | |
return lastType.add(typeDeclaration, bracketBalanceValue); | |
} | |
} | |
if (this.types == null) { | |
this.types = new RecoveredType[5]; | |
this.typeCount = 0; | |
} else { | |
if (this.typeCount == this.types.length) { | |
System.arraycopy( | |
this.types, | |
0, | |
(this.types = new RecoveredType[2 * this.typeCount]), | |
0, | |
this.typeCount); | |
} | |
} | |
RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue); | |
this.types[this.typeCount++] = element; | |
/* if type not finished, then type becomes current */ | |
if (typeDeclaration.declarationSourceEnd == 0) return element; | |
return this; | |
} | |
/* | |
* Answer the associated parsed structure | |
*/ | |
public ASTNode parseTree(){ | |
return this.unitDeclaration; | |
} | |
/* | |
* Answer the very source end of the corresponding parse node | |
*/ | |
public int sourceEnd(){ | |
return this.unitDeclaration.sourceEnd; | |
} | |
public String toString(int tab) { | |
StringBuffer result = new StringBuffer(tabString(tab)); | |
result.append("Recovered unit: [\n"); //$NON-NLS-1$ | |
this.unitDeclaration.print(tab + 1, result); | |
result.append(tabString(tab + 1)); | |
result.append("]"); //$NON-NLS-1$ | |
if (this.imports != null) { | |
for (int i = 0; i < this.importCount; i++) { | |
result.append("\n"); //$NON-NLS-1$ | |
result.append(this.imports[i].toString(tab + 1)); | |
} | |
} | |
if (this.types != null) { | |
for (int i = 0; i < this.typeCount; i++) { | |
result.append("\n"); //$NON-NLS-1$ | |
result.append(this.types[i].toString(tab + 1)); | |
} | |
} | |
return result.toString(); | |
} | |
public CompilationUnitDeclaration updatedCompilationUnitDeclaration(){ | |
/* update imports */ | |
if (this.importCount > 0){ | |
ImportReference[] importRefences = new ImportReference[this.importCount]; | |
for (int i = 0; i < this.importCount; i++){ | |
importRefences[i] = this.imports[i].updatedImportReference(); | |
} | |
this.unitDeclaration.imports = importRefences; | |
} | |
/* update types */ | |
if (this.typeCount > 0){ | |
int existingCount = this.unitDeclaration.types == null ? 0 : this.unitDeclaration.types.length; | |
TypeDeclaration[] typeDeclarations = new TypeDeclaration[existingCount + this.typeCount]; | |
if (existingCount > 0){ | |
System.arraycopy(this.unitDeclaration.types, 0, typeDeclarations, 0, existingCount); | |
} | |
// may need to update the declarationSourceEnd of the last type | |
if (this.types[this.typeCount - 1].typeDeclaration.declarationSourceEnd == 0){ | |
this.types[this.typeCount - 1].typeDeclaration.declarationSourceEnd = this.unitDeclaration.sourceEnd; | |
this.types[this.typeCount - 1].typeDeclaration.bodyEnd = this.unitDeclaration.sourceEnd; | |
} | |
int actualCount = existingCount; | |
for (int i = 0; i < this.typeCount; i++){ | |
TypeDeclaration typeDecl = this.types[i].updatedTypeDeclaration(); | |
// filter out local types (12454) | |
if ((typeDecl.bits & ASTNode.IsLocalTypeMASK) == 0){ | |
typeDeclarations[actualCount++] = typeDecl; | |
} | |
} | |
if (actualCount != this.typeCount){ | |
System.arraycopy( | |
typeDeclarations, | |
0, | |
typeDeclarations = new TypeDeclaration[existingCount+actualCount], | |
0, | |
existingCount+actualCount); | |
} | |
this.unitDeclaration.types = typeDeclarations; | |
} | |
return this.unitDeclaration; | |
} | |
public void updateParseTree(){ | |
this.updatedCompilationUnitDeclaration(); | |
} | |
/* | |
* Update the sourceEnd of the corresponding parse node | |
*/ | |
public void updateSourceEndIfNecessary(int bodyStart, int bodyEnd){ | |
if (this.unitDeclaration.sourceEnd == 0) | |
this.unitDeclaration.sourceEnd = bodyEnd; | |
} | |
} |