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.phpeclipse.internal.compiler.ast.ASTNode;
14 import net.sourceforge.phpeclipse.internal.compiler.ast.Block;
15 import net.sourceforge.phpeclipse.internal.compiler.ast.Statement;
18 * Internal structure for parsing recovery
21 public class RecoveredElement {
23 public RecoveredElement parent;
24 public int bracketBalance;
25 public boolean foundOpeningBrace;
26 protected Parser recoveringParser;
27 public RecoveredElement(RecoveredElement parent, int bracketBalance){
28 this(parent, bracketBalance, null);
30 public RecoveredElement(RecoveredElement parent, int bracketBalance, Parser parser){
32 this.bracketBalance = bracketBalance;
33 this.recoveringParser = parser;
36 * Record a method declaration
38 //public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalance) {
40 // /* default behavior is to delegate recording to parent if any */
41 // if (parent == null) {
42 // return this; // ignore
44 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(methodDeclaration.declarationSourceStart - 1));
45 // return this.parent.add(methodDeclaration, bracketBalance);
49 * Record a nested block declaration
51 public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) {
53 /* default behavior is to delegate recording to parent if any */
55 return this; // ignore
57 this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(nestedBlockDeclaration.sourceStart - 1));
58 return this.parent.add(nestedBlockDeclaration, bracketBalance);
62 * Record a field declaration
64 //public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalance) {
66 // /* default behavior is to delegate recording to parent if any */
67 // if (parent == null) {
68 // return this; // ignore
70 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1));
71 // return this.parent.add(fieldDeclaration, bracketBalance);
75 // * Record an import reference
77 //public RecoveredElement add(ImportReference importReference, int bracketBalance){
79 // /* default behavior is to delegate recording to parent if any */
80 // if (parent == null) {
81 // return this; // ignore
83 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(importReference.declarationSourceStart - 1));
84 // return this.parent.add(importReference, bracketBalance);
88 // * Record a local declaration
90 //public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalance) {
92 // /* default behavior is to delegate recording to parent if any */
93 // if (parent == null) {
94 // return this; // ignore
96 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1));
97 // return this.parent.add(localDeclaration, bracketBalance);
103 public RecoveredElement add(Statement statement, int bracketBalance) {
105 /* default behavior is to delegate recording to parent if any */
106 if (parent == null) {
107 return this; // ignore
109 this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(statement.sourceStart - 1));
110 return this.parent.add(statement, bracketBalance);
114 * Record a type declaration
116 //public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance){
118 // /* default behavior is to delegate recording to parent if any */
119 // if (parent == null) {
120 // return this; // ignore
122 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1));
123 // return this.parent.add(typeDeclaration, bracketBalance);
127 * Answer the depth of this element, considering the parent link.
131 RecoveredElement current = this;
132 while ((current = current.parent) != null) depth++;
136 * Answer the enclosing method node, or null if none
138 //public RecoveredInitializer enclosingInitializer(){
139 // RecoveredElement current = this;
140 // while (current != null){
141 // if (current instanceof RecoveredInitializer){
142 // return (RecoveredInitializer) current;
144 // current = current.parent;
149 * Answer the enclosing method node, or null if none
151 //public RecoveredMethod enclosingMethod(){
152 // RecoveredElement current = this;
153 // while (current != null){
154 // if (current instanceof RecoveredMethod){
155 // return (RecoveredMethod) current;
157 // current = current.parent;
162 * Answer the enclosing type node, or null if none
164 //public RecoveredType enclosingType(){
165 // RecoveredElement current = this;
166 // while (current != null){
167 // if (current instanceof RecoveredType){
168 // return (RecoveredType) current;
170 // current = current.parent;
175 * Answer the closest specified parser
177 public Parser parser(){
178 RecoveredElement current = this;
179 while (current != null){
180 if (current.recoveringParser != null){
181 return current.recoveringParser;
183 current = current.parent;
188 * Answer the associated parsed structure
190 public ASTNode parseTree(){
194 * Iterate the enclosing blocks and tag them so as to preserve their content
196 //public void preserveEnclosingBlocks(){
197 // RecoveredElement current = this;
198 // while (current != null){
199 // if (current instanceof RecoveredBlock){
200 // ((RecoveredBlock)current).preserveContent = true;
202 // if (current instanceof RecoveredType){ // for anonymous types
203 // ((RecoveredType)current).preserveContent = true;
205 // current = current.parent;
209 * Answer the position of the previous line end if
210 * there is nothing but spaces in between it and the
211 * line end. Used to trim spaces on unclosed elements.
213 public int previousAvailableLineEnd(int position){
215 Parser parser = this.parser();
216 if (parser == null) return position;
218 Scanner scanner = parser.scanner;
219 if (scanner.lineEnds == null) return position;
221 int index = scanner.getLineNumber(position);
222 if (index < 2) return position;
223 int previousLineEnd = scanner.lineEnds[index-2];
225 char[] source = scanner.source;
226 for (int i = previousLineEnd+1; i < position; i++){
227 if (!(source[i] == ' ' || source[i] == '\t')) return position;
229 return previousLineEnd;
232 * Answer the very source end of the corresponding parse node
234 public int sourceEnd(){
237 protected String tabString(int tab) {
238 StringBuffer result = new StringBuffer();
239 for (int i = tab; i > 0; i--) {
240 result.append(" "); //$NON-NLS-1$
242 return result.toString();
245 * Answer the top node
247 public RecoveredElement topElement(){
248 RecoveredElement current = this;
249 while (current.parent != null){
250 current = current.parent;
254 public String toString() {
257 public String toString(int tab) {
258 return super.toString();
261 * Answer the enclosing type node, or null if none
263 //public RecoveredType type(){
264 // RecoveredElement current = this;
265 // while (current != null){
266 // if (current instanceof RecoveredType){
267 // return (RecoveredType) current;
269 // current = current.parent;
274 * Update the bodyStart of the corresponding parse node
276 public void updateBodyStart(int bodyStart){
277 this.foundOpeningBrace = true;
280 * Update the corresponding parse node from parser state which
281 * is about to disappear because of restarting recovery
283 public void updateFromParserState(){
286 * A closing brace got consumed, might have closed the current element,
287 * in which case both the currentElement is exited
289 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
290 if ((--bracketBalance <= 0) && (parent != null)){
291 this.updateSourceEndIfNecessary(braceEnd);
297 * An opening brace got consumed, might be the expected opening one of the current element,
298 * in which case the bodyStart is updated.
300 public RecoveredElement updateOnOpeningBrace(int braceEnd){
302 if (bracketBalance++ == 0){
303 this.updateBodyStart(braceEnd + 1);
306 return null; // no update is necessary
309 * Final update the corresponding parse node
311 public void updateParseTree(){
314 * Update the declarationSourceEnd of the corresponding parse node
316 public void updateSourceEndIfNecessary(int sourceEnd){