1 /*******************************************************************************
 
   2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
 
   3  * All rights reserved. This program and the accompanying materials 
 
   4  * are made available under the terms of the Common Public License v0.5 
 
   5  * which accompanies this distribution, and is available at
 
   6  * http://www.eclipse.org/legal/cpl-v05.html
 
   9  *     IBM Corporation - initial API and implementation
 
  10  ******************************************************************************/
 
  11 package net.sourceforge.phpdt.internal.compiler.parser;
 
  14  * Internal initializer structure for parsing recovery 
 
  16 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
 
  17 import net.sourceforge.phpdt.internal.compiler.ast.AstNode;
 
  18 import net.sourceforge.phpdt.internal.compiler.ast.Block;
 
  19 import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration;
 
  20 import net.sourceforge.phpdt.internal.compiler.ast.Initializer;
 
  21 import net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration;
 
  22 import net.sourceforge.phpdt.internal.compiler.ast.LocalTypeDeclaration;
 
  23 import net.sourceforge.phpdt.internal.compiler.ast.Statement;
 
  24 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
 
  25 import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypes;
 
  26 import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers;
 
  27 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
 
  29 public class RecoveredInitializer extends RecoveredField implements CompilerModifiers, ITerminalSymbols, BaseTypes {
 
  31         public RecoveredType[] localTypes;
 
  32         public int localTypeCount;
 
  34         public RecoveredBlock initializerBody;  
 
  35 public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance){
 
  36         this(fieldDeclaration, parent, bracketBalance, null);
 
  38 public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){
 
  39         super(fieldDeclaration, parent, bracketBalance, parser);
 
  40         this.foundOpeningBrace = true;
 
  43  * Record a nested block declaration
 
  45 public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) {
 
  47         /* default behavior is to delegate recording to parent if any,
 
  48         do not consider elements passed the known end (if set)
 
  49         it must be belonging to an enclosing element 
 
  51         if (fieldDeclaration.declarationSourceEnd > 0
 
  52                 && nestedBlockDeclaration.sourceStart
 
  53                         > fieldDeclaration.declarationSourceEnd){
 
  54                 if (this.parent == null){
 
  55                         return this; // ignore
 
  57                         return this.parent.add(nestedBlockDeclaration, bracketBalance);
 
  60         /* consider that if the opening brace was not found, it is there */
 
  61         if (!foundOpeningBrace){
 
  62                 foundOpeningBrace = true;
 
  63                 this.bracketBalance++;
 
  66         initializerBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalance);
 
  67         if (nestedBlockDeclaration.sourceEnd == 0) return initializerBody;
 
  71  * Record a field declaration (act like inside method body)
 
  73 public RecoveredElement add(FieldDeclaration newFieldDeclaration, int bracketBalance) {
 
  75         /* local variables inside initializer can only be final and non void */
 
  76         char[][] fieldTypeName;
 
  77         if ((newFieldDeclaration.modifiers & ~AccFinal) != 0 /* local var can only be final */
 
  78                 || (newFieldDeclaration.type == null) // initializer
 
  79                 || ((fieldTypeName = newFieldDeclaration.type.getTypeName()).length == 1 // non void
 
  80                         && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))){ 
 
  81                 if (this.parent == null) {
 
  82                         return this; // ignore
 
  84                         this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(newFieldDeclaration.declarationSourceStart - 1));
 
  85                         return this.parent.add(newFieldDeclaration, bracketBalance);
 
  89         /* default behavior is to delegate recording to parent if any,
 
  90         do not consider elements passed the known end (if set)
 
  91         it must be belonging to an enclosing element 
 
  93         if (this.fieldDeclaration.declarationSourceEnd > 0
 
  94                 && newFieldDeclaration.declarationSourceStart
 
  95                         > this.fieldDeclaration.declarationSourceEnd){
 
  96                 if (this.parent == null) {
 
  97                         return this; // ignore
 
  99                         return this.parent.add(newFieldDeclaration, bracketBalance);
 
 102         // still inside initializer, treat as local variable
 
 103         return this; // ignore
 
 106  * Record a local declaration - regular method should have been created a block body
 
 108 public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalance) {
 
 110         /* do not consider a type starting passed the type end (if set)
 
 111                 it must be belonging to an enclosing type */
 
 112         if (fieldDeclaration.declarationSourceEnd != 0 
 
 113                 && localDeclaration.declarationSourceStart > fieldDeclaration.declarationSourceEnd){
 
 114                 if (parent == null) {
 
 115                         return this; // ignore
 
 117                         return this.parent.add(localDeclaration, bracketBalance);
 
 120         /* method body should have been created */
 
 121         Block block = new Block(0);
 
 122         block.sourceStart = ((Initializer)fieldDeclaration).bodyStart;
 
 123         RecoveredElement element = this.add(block, 1);
 
 124         return element.add(localDeclaration, bracketBalance);   
 
 127  * Record a statement - regular method should have been created a block body
 
 129 public RecoveredElement add(Statement statement, int bracketBalance) {
 
 131         /* do not consider a statement starting passed the initializer end (if set)
 
 132                 it must be belonging to an enclosing type */
 
 133         if (fieldDeclaration.declarationSourceEnd != 0 
 
 134                 && statement.sourceStart > fieldDeclaration.declarationSourceEnd){
 
 135                 if (parent == null) {
 
 136                         return this; // ignore
 
 138                         return this.parent.add(statement, bracketBalance);
 
 141         /* initializer body should have been created */
 
 142         Block block = new Block(0);
 
 143         block.sourceStart = ((Initializer)fieldDeclaration).bodyStart;
 
 144         RecoveredElement element = this.add(block, 1);
 
 145         return element.add(statement, bracketBalance);  
 
 147 public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance) {
 
 149         /* do not consider a type starting passed the type end (if set)
 
 150                 it must be belonging to an enclosing type */
 
 151         if (fieldDeclaration.declarationSourceEnd != 0 
 
 152                 && typeDeclaration.declarationSourceStart > fieldDeclaration.declarationSourceEnd){
 
 153                 if (parent == null) {
 
 154                         return this; // ignore
 
 156                         return this.parent.add(typeDeclaration, bracketBalance);
 
 159         if (typeDeclaration instanceof LocalTypeDeclaration){
 
 160                 /* method body should have been created */
 
 161                 Block block = new Block(0);
 
 162                 block.sourceStart = ((Initializer)fieldDeclaration).bodyStart;
 
 163                 RecoveredElement element = this.add(block, 1);
 
 164                 return element.add(typeDeclaration, bracketBalance);    
 
 166         if (localTypes == null) {
 
 167                 localTypes = new RecoveredType[5];
 
 170                 if (localTypeCount == localTypes.length) {
 
 174                                 (localTypes = new RecoveredType[2 * localTypeCount]), 
 
 179         RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalance);
 
 180         localTypes[localTypeCount++] = element;
 
 182         /* consider that if the opening brace was not found, it is there */
 
 183         if (!foundOpeningBrace){
 
 184                 foundOpeningBrace = true;
 
 185                 this.bracketBalance++;
 
 189 public String toString(int tab) {
 
 190         StringBuffer result = new StringBuffer(tabString(tab));
 
 191         result.append("Recovered initializer:\n"); //$NON-NLS-1$
 
 192         result.append(this.fieldDeclaration.toString(tab + 1));
 
 193         if (this.initializerBody != null) {
 
 194                 result.append("\n"); //$NON-NLS-1$
 
 195                 result.append(this.initializerBody.toString(tab + 1));
 
 197         return result.toString();
 
 199 public FieldDeclaration updatedFieldDeclaration(){
 
 201         if (initializerBody != null){
 
 202                 Block block = initializerBody.updatedBlock();
 
 204                         ((Initializer)fieldDeclaration).block = block;
 
 206                 if (this.localTypeCount > 0) fieldDeclaration.bits |= AstNode.HasLocalTypeMASK;
 
 209         if (fieldDeclaration.sourceEnd == 0){
 
 210                 fieldDeclaration.sourceEnd = fieldDeclaration.declarationSourceEnd;
 
 212         return fieldDeclaration;
 
 215  * A closing brace got consumed, might have closed the current element,
 
 216  * in which case both the currentElement is exited
 
 218 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
 
 219         if ((--bracketBalance <= 0) && (parent != null)){
 
 220                 this.updateSourceEndIfNecessary(braceEnd);
 
 226  * An opening brace got consumed, might be the expected opening one of the current element,
 
 227  * in which case the bodyStart is updated.
 
 229 public RecoveredElement updateOnOpeningBrace(int currentPosition){
 
 231         return this; // request to restart
 
 234  * Update the declarationSourceEnd of the corresponding parse node
 
 236 public void updateSourceEndIfNecessary(int sourceEnd){
 
 237         if (this.fieldDeclaration.declarationSourceEnd == 0) {
 
 238                 this.fieldDeclaration.sourceEnd = sourceEnd;
 
 239                 this.fieldDeclaration.declarationSourceEnd = sourceEnd;
 
 240                 this.fieldDeclaration.declarationEnd = sourceEnd;