1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.parser;
13 import net.sourceforge.phpdt.internal.compiler.ast.ASTNode;
14 import net.sourceforge.phpdt.internal.compiler.ast.Block;
15 import net.sourceforge.phpdt.internal.compiler.ast.Statement;
18 * Internal structure for parsing recovery
20 public class RecoveredElement {
22 public RecoveredElement parent;
23 public int bracketBalance;
24 public boolean foundOpeningBrace;
25 protected Parser recoveringParser;
26 public RecoveredElement(RecoveredElement parent, int bracketBalance){
27 this(parent, bracketBalance, null);
29 public RecoveredElement(RecoveredElement parent, int bracketBalance, Parser parser){
31 this.bracketBalance = bracketBalance;
32 this.recoveringParser = parser;
35 * Record a method declaration
37 //public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalance) {
39 // /* default behavior is to delegate recording to parent if any */
40 // if (parent == null) {
41 // return this; // ignore
43 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(methodDeclaration.declarationSourceStart - 1));
44 // return this.parent.add(methodDeclaration, bracketBalance);
48 * Record a nested block declaration
50 public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) {
52 /* default behavior is to delegate recording to parent if any */
54 return this; // ignore
56 this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(nestedBlockDeclaration.sourceStart - 1));
57 return this.parent.add(nestedBlockDeclaration, bracketBalance);
61 * Record a field declaration
63 //public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalance) {
65 // /* default behavior is to delegate recording to parent if any */
66 // if (parent == null) {
67 // return this; // ignore
69 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1));
70 // return this.parent.add(fieldDeclaration, bracketBalance);
74 // * Record an import reference
76 //public RecoveredElement add(ImportReference importReference, int bracketBalance){
78 // /* default behavior is to delegate recording to parent if any */
79 // if (parent == null) {
80 // return this; // ignore
82 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(importReference.declarationSourceStart - 1));
83 // return this.parent.add(importReference, bracketBalance);
87 // * Record a local declaration
89 //public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalance) {
91 // /* default behavior is to delegate recording to parent if any */
92 // if (parent == null) {
93 // return this; // ignore
95 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1));
96 // return this.parent.add(localDeclaration, bracketBalance);
102 public RecoveredElement add(Statement statement, int bracketBalance) {
104 /* default behavior is to delegate recording to parent if any */
105 if (parent == null) {
106 return this; // ignore
108 this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(statement.sourceStart - 1));
109 return this.parent.add(statement, bracketBalance);
113 * Record a type declaration
115 //public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance){
117 // /* default behavior is to delegate recording to parent if any */
118 // if (parent == null) {
119 // return this; // ignore
121 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1));
122 // return this.parent.add(typeDeclaration, bracketBalance);
126 * Answer the depth of this element, considering the parent link.
130 RecoveredElement current = this;
131 while ((current = current.parent) != null) depth++;
135 * Answer the enclosing method node, or null if none
137 //public RecoveredInitializer enclosingInitializer(){
138 // RecoveredElement current = this;
139 // while (current != null){
140 // if (current instanceof RecoveredInitializer){
141 // return (RecoveredInitializer) current;
143 // current = current.parent;
148 * Answer the enclosing method node, or null if none
150 //public RecoveredMethod enclosingMethod(){
151 // RecoveredElement current = this;
152 // while (current != null){
153 // if (current instanceof RecoveredMethod){
154 // return (RecoveredMethod) current;
156 // current = current.parent;
161 * Answer the enclosing type node, or null if none
163 //public RecoveredType enclosingType(){
164 // RecoveredElement current = this;
165 // while (current != null){
166 // if (current instanceof RecoveredType){
167 // return (RecoveredType) current;
169 // current = current.parent;
174 * Answer the closest specified parser
176 public Parser parser(){
177 RecoveredElement current = this;
178 while (current != null){
179 if (current.recoveringParser != null){
180 return current.recoveringParser;
182 current = current.parent;
187 * Answer the associated parsed structure
189 public ASTNode parseTree(){
193 * Iterate the enclosing blocks and tag them so as to preserve their content
195 //public void preserveEnclosingBlocks(){
196 // RecoveredElement current = this;
197 // while (current != null){
198 // if (current instanceof RecoveredBlock){
199 // ((RecoveredBlock)current).preserveContent = true;
201 // if (current instanceof RecoveredType){ // for anonymous types
202 // ((RecoveredType)current).preserveContent = true;
204 // current = current.parent;
208 * Answer the position of the previous line end if
209 * there is nothing but spaces in between it and the
210 * line end. Used to trim spaces on unclosed elements.
212 public int previousAvailableLineEnd(int position){
214 Parser parser = this.parser();
215 if (parser == null) return position;
217 Scanner scanner = parser.scanner;
218 if (scanner.lineEnds == null) return position;
220 int index = scanner.getLineNumber(position);
221 if (index < 2) return position;
222 int previousLineEnd = scanner.lineEnds[index-2];
224 char[] source = scanner.source;
225 for (int i = previousLineEnd+1; i < position; i++){
226 if (!(source[i] == ' ' || source[i] == '\t')) return position;
228 return previousLineEnd;
231 * Answer the very source end of the corresponding parse node
233 public int sourceEnd(){
236 protected String tabString(int tab) {
237 StringBuffer result = new StringBuffer();
238 for (int i = tab; i > 0; i--) {
239 result.append(" "); //$NON-NLS-1$
241 return result.toString();
244 * Answer the top node
246 public RecoveredElement topElement(){
247 RecoveredElement current = this;
248 while (current.parent != null){
249 current = current.parent;
253 public String toString() {
256 public String toString(int tab) {
257 return super.toString();
260 * Answer the enclosing type node, or null if none
262 //public RecoveredType type(){
263 // RecoveredElement current = this;
264 // while (current != null){
265 // if (current instanceof RecoveredType){
266 // return (RecoveredType) current;
268 // current = current.parent;
273 * Update the bodyStart of the corresponding parse node
275 public void updateBodyStart(int bodyStart){
276 this.foundOpeningBrace = true;
279 * Update the corresponding parse node from parser state which
280 * is about to disappear because of restarting recovery
282 public void updateFromParserState(){
285 * A closing brace got consumed, might have closed the current element,
286 * in which case both the currentElement is exited
288 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
289 if ((--bracketBalance <= 0) && (parent != null)){
290 this.updateSourceEndIfNecessary(braceEnd);
296 * An opening brace got consumed, might be the expected opening one of the current element,
297 * in which case the bodyStart is updated.
299 public RecoveredElement updateOnOpeningBrace(int braceEnd){
301 if (bracketBalance++ == 0){
302 this.updateBodyStart(braceEnd + 1);
305 return null; // no update is necessary
308 * Final update the corresponding parse node
310 public void updateParseTree(){
313 * Update the declarationSourceEnd of the corresponding parse node
315 public void updateSourceEndIfNecessary(int sourceEnd){