/******************************************************************************* | |
* 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 initializer structure for parsing recovery | |
*/ | |
import org.eclipse.wst.jsdt.core.compiler.*; | |
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.FieldDeclaration; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.Initializer; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.LocalDeclaration; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.Statement; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.TypeDeclaration; | |
import org.eclipse.wst.jsdt.internal.compiler.lookup.BaseTypes; | |
import org.eclipse.wst.jsdt.internal.compiler.lookup.CompilerModifiers; | |
public class RecoveredInitializer extends RecoveredField implements CompilerModifiers, TerminalTokens, BaseTypes { | |
public RecoveredType[] localTypes; | |
public int localTypeCount; | |
public RecoveredBlock initializerBody; | |
public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance){ | |
this(fieldDeclaration, parent, bracketBalance, null); | |
} | |
public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){ | |
super(fieldDeclaration, parent, bracketBalance, parser); | |
this.foundOpeningBrace = true; | |
} | |
/* | |
* Record a nested block declaration | |
*/ | |
public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) { | |
/* default behavior is to delegate recording to parent if any, | |
do not consider elements passed the known end (if set) | |
it must be belonging to an enclosing element | |
*/ | |
if (fieldDeclaration.declarationSourceEnd > 0 | |
&& nestedBlockDeclaration.sourceStart > fieldDeclaration.declarationSourceEnd){ | |
if (this.parent == null) return this; // ignore | |
return this.parent.add(nestedBlockDeclaration, bracketBalanceValue); | |
} | |
/* consider that if the opening brace was not found, it is there */ | |
if (!foundOpeningBrace){ | |
foundOpeningBrace = true; | |
this.bracketBalance++; | |
} | |
initializerBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalanceValue); | |
if (nestedBlockDeclaration.sourceEnd == 0) return initializerBody; | |
return this; | |
} | |
/* | |
* Record a field declaration (act like inside method body) | |
*/ | |
public RecoveredElement add(FieldDeclaration newFieldDeclaration, int bracketBalanceValue) { | |
/* local variables inside initializer can only be final and non void */ | |
char[][] fieldTypeName; | |
if ((newFieldDeclaration.modifiers & ~AccFinal) != 0 /* local var can only be final */ | |
|| (newFieldDeclaration.type == null) // initializer | |
|| ((fieldTypeName = newFieldDeclaration.type.getTypeName()).length == 1 // non void | |
&& CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))){ | |
if (this.parent == null) return this; // ignore | |
this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(newFieldDeclaration.declarationSourceStart - 1)); | |
return this.parent.add(newFieldDeclaration, bracketBalanceValue); | |
} | |
/* default behavior is to delegate recording to parent if any, | |
do not consider elements passed the known end (if set) | |
it must be belonging to an enclosing element | |
*/ | |
if (this.fieldDeclaration.declarationSourceEnd > 0 | |
&& newFieldDeclaration.declarationSourceStart > this.fieldDeclaration.declarationSourceEnd){ | |
if (this.parent == null) return this; // ignore | |
return this.parent.add(newFieldDeclaration, bracketBalanceValue); | |
} | |
// still inside initializer, treat as local variable | |
return this; // ignore | |
} | |
/* | |
* Record a local declaration - regular method should have been created a block body | |
*/ | |
public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue) { | |
/* do not consider a type starting passed the type end (if set) | |
it must be belonging to an enclosing type */ | |
if (fieldDeclaration.declarationSourceEnd != 0 | |
&& localDeclaration.declarationSourceStart > fieldDeclaration.declarationSourceEnd){ | |
if (parent == null) return this; // ignore | |
return this.parent.add(localDeclaration, bracketBalanceValue); | |
} | |
/* method body should have been created */ | |
Block block = new Block(0); | |
block.sourceStart = ((Initializer)fieldDeclaration).sourceStart; | |
RecoveredElement element = this.add(block, 1); | |
return element.add(localDeclaration, bracketBalanceValue); | |
} | |
/* | |
* Record a statement - regular method should have been created a block body | |
*/ | |
public RecoveredElement add(Statement statement, int bracketBalanceValue) { | |
/* do not consider a statement starting passed the initializer end (if set) | |
it must be belonging to an enclosing type */ | |
if (fieldDeclaration.declarationSourceEnd != 0 | |
&& statement.sourceStart > fieldDeclaration.declarationSourceEnd){ | |
if (parent == null) return this; // ignore | |
return this.parent.add(statement, bracketBalanceValue); | |
} | |
/* initializer body should have been created */ | |
Block block = new Block(0); | |
block.sourceStart = ((Initializer)fieldDeclaration).sourceStart; | |
RecoveredElement element = this.add(block, 1); | |
return element.add(statement, bracketBalanceValue); | |
} | |
public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) { | |
/* do not consider a type starting passed the type end (if set) | |
it must be belonging to an enclosing type */ | |
if (fieldDeclaration.declarationSourceEnd != 0 | |
&& typeDeclaration.declarationSourceStart > fieldDeclaration.declarationSourceEnd){ | |
if (parent == null) return this; // ignore | |
return this.parent.add(typeDeclaration, bracketBalanceValue); | |
} | |
if ((typeDeclaration.bits & ASTNode.IsLocalTypeMASK) != 0){ | |
/* method body should have been created */ | |
Block block = new Block(0); | |
block.sourceStart = ((Initializer)fieldDeclaration).sourceStart; | |
RecoveredElement element = this.add(block, 1); | |
return element.add(typeDeclaration, bracketBalanceValue); | |
} | |
if (localTypes == null) { | |
localTypes = new RecoveredType[5]; | |
localTypeCount = 0; | |
} else { | |
if (localTypeCount == localTypes.length) { | |
System.arraycopy( | |
localTypes, | |
0, | |
(localTypes = new RecoveredType[2 * localTypeCount]), | |
0, | |
localTypeCount); | |
} | |
} | |
RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue); | |
localTypes[localTypeCount++] = element; | |
/* consider that if the opening brace was not found, it is there */ | |
if (!foundOpeningBrace){ | |
foundOpeningBrace = true; | |
this.bracketBalance++; | |
} | |
return element; | |
} | |
public String toString(int tab) { | |
StringBuffer result = new StringBuffer(tabString(tab)); | |
result.append("Recovered initializer:\n"); //$NON-NLS-1$ | |
this.fieldDeclaration.print(tab + 1, result); | |
if (this.initializerBody != null) { | |
result.append("\n"); //$NON-NLS-1$ | |
result.append(this.initializerBody.toString(tab + 1)); | |
} | |
return result.toString(); | |
} | |
public FieldDeclaration updatedFieldDeclaration(){ | |
if (initializerBody != null){ | |
Block block = initializerBody.updatedBlock(); | |
if (block != null){ | |
((Initializer)fieldDeclaration).block = block; | |
} | |
if (this.localTypeCount > 0) fieldDeclaration.bits |= ASTNode.HasLocalTypeMASK; | |
} | |
if (fieldDeclaration.sourceEnd == 0){ | |
fieldDeclaration.sourceEnd = fieldDeclaration.declarationSourceEnd; | |
} | |
return fieldDeclaration; | |
} | |
/* | |
* A closing brace got consumed, might have closed the current element, | |
* in which case both the currentElement is exited | |
*/ | |
public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ | |
if ((--bracketBalance <= 0) && (parent != null)){ | |
this.updateSourceEndIfNecessary(braceStart, braceEnd); | |
return parent; | |
} | |
return this; | |
} | |
/* | |
* An opening brace got consumed, might be the expected opening one of the current element, | |
* in which case the bodyStart is updated. | |
*/ | |
public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){ | |
bracketBalance++; | |
return this; // request to restart | |
} | |
/* | |
* Update the declarationSourceEnd of the corresponding parse node | |
*/ | |
public void updateSourceEndIfNecessary(int braceStart, int braceEnd){ | |
if (this.fieldDeclaration.declarationSourceEnd == 0) { | |
Initializer initializer = (Initializer)fieldDeclaration; | |
if(parser().rBraceSuccessorStart >= braceEnd) { | |
if (initializer.bodyStart < parser().rBraceEnd) { | |
initializer.declarationSourceEnd = parser().rBraceEnd; | |
} else { | |
initializer.declarationSourceEnd = initializer.bodyStart; | |
} | |
if (initializer.bodyStart < parser().rBraceStart) { | |
initializer.bodyEnd = parser().rBraceStart; | |
} else { | |
initializer.bodyEnd = initializer.bodyStart; | |
} | |
} else { | |
initializer.declarationSourceEnd = braceEnd; | |
initializer.bodyEnd = braceStart - 1; | |
} | |
if(initializer.block != null) { | |
initializer.block.sourceEnd = initializer.declarationSourceEnd; | |
} | |
} | |
} | |
} |