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;
24 public int bracketBalance;
26 public boolean foundOpeningBrace;
28 protected Parser recoveringParser;
30 public RecoveredElement(RecoveredElement parent, int bracketBalance) {
31 this(parent, bracketBalance, null);
34 public RecoveredElement(RecoveredElement parent, int bracketBalance,
37 this.bracketBalance = bracketBalance;
38 this.recoveringParser = parser;
42 * Record a method declaration
44 // public RecoveredElement add(AbstractMethodDeclaration methodDeclaration,
45 // int bracketBalance) {
47 // /* default behavior is to delegate recording to parent if any */
48 // if (parent == null) {
49 // return this; // ignore
51 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(methodDeclaration.declarationSourceStart
53 // return this.parent.add(methodDeclaration, bracketBalance);
57 * Record a nested block declaration
59 public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) {
61 /* default behavior is to delegate recording to parent if any */
63 return this; // ignore
66 .updateSourceEndIfNecessary(this
67 .previousAvailableLineEnd(nestedBlockDeclaration.sourceStart - 1));
68 return this.parent.add(nestedBlockDeclaration, bracketBalance);
73 * Record a field declaration
75 // public RecoveredElement add(FieldDeclaration fieldDeclaration, int
78 // /* default behavior is to delegate recording to parent if any */
79 // if (parent == null) {
80 // return this; // ignore
82 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart
84 // return this.parent.add(fieldDeclaration, bracketBalance);
88 // * Record an import reference
90 // public RecoveredElement add(ImportReference importReference, int
93 // /* default behavior is to delegate recording to parent if any */
94 // if (parent == null) {
95 // return this; // ignore
97 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(importReference.declarationSourceStart
99 // return this.parent.add(importReference, bracketBalance);
103 // * Record a local declaration
105 // public RecoveredElement add(LocalDeclaration localDeclaration, int
108 // /* default behavior is to delegate recording to parent if any */
109 // if (parent == null) {
110 // return this; // ignore
112 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart
114 // return this.parent.add(localDeclaration, bracketBalance);
120 public RecoveredElement add(Statement statement, int bracketBalance) {
122 /* default behavior is to delegate recording to parent if any */
123 if (parent == null) {
124 return this; // ignore
126 this.updateSourceEndIfNecessary(this
127 .previousAvailableLineEnd(statement.sourceStart - 1));
128 return this.parent.add(statement, bracketBalance);
133 * Record a type declaration
135 // public RecoveredElement add(TypeDeclaration typeDeclaration, int
138 // /* default behavior is to delegate recording to parent if any */
139 // if (parent == null) {
140 // return this; // ignore
142 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart
144 // return this.parent.add(typeDeclaration, bracketBalance);
148 * Answer the depth of this element, considering the parent link.
152 RecoveredElement current = this;
153 while ((current = current.parent) != null)
159 * Answer the enclosing method node, or null if none
161 // public RecoveredInitializer enclosingInitializer(){
162 // RecoveredElement current = this;
163 // while (current != null){
164 // if (current instanceof RecoveredInitializer){
165 // return (RecoveredInitializer) current;
167 // current = current.parent;
172 * Answer the enclosing method node, or null if none
174 // public RecoveredMethod enclosingMethod(){
175 // RecoveredElement current = this;
176 // while (current != null){
177 // if (current instanceof RecoveredMethod){
178 // return (RecoveredMethod) current;
180 // current = current.parent;
185 * Answer the enclosing type node, or null if none
187 // public RecoveredType enclosingType(){
188 // RecoveredElement current = this;
189 // while (current != null){
190 // if (current instanceof RecoveredType){
191 // return (RecoveredType) current;
193 // current = current.parent;
198 * Answer the closest specified parser
200 public Parser parser() {
201 RecoveredElement current = this;
202 while (current != null) {
203 if (current.recoveringParser != null) {
204 return current.recoveringParser;
206 current = current.parent;
212 * Answer the associated parsed structure
214 public ASTNode parseTree() {
219 * Iterate the enclosing blocks and tag them so as to preserve their content
221 // public void preserveEnclosingBlocks(){
222 // RecoveredElement current = this;
223 // while (current != null){
224 // if (current instanceof RecoveredBlock){
225 // ((RecoveredBlock)current).preserveContent = true;
227 // if (current instanceof RecoveredType){ // for anonymous types
228 // ((RecoveredType)current).preserveContent = true;
230 // current = current.parent;
234 * Answer the position of the previous line end if there is nothing but
235 * spaces in between it and the line end. Used to trim spaces on unclosed
238 public int previousAvailableLineEnd(int position) {
240 Parser parser = this.parser();
244 Scanner scanner = parser.scanner;
245 if (scanner.lineEnds == null)
248 int index = scanner.getLineNumber(position);
251 int previousLineEnd = scanner.lineEnds[index - 2];
253 char[] source = scanner.source;
254 for (int i = previousLineEnd + 1; i < position; i++) {
255 if (!(source[i] == ' ' || source[i] == '\t'))
258 return previousLineEnd;
262 * Answer the very source end of the corresponding parse node
264 public int sourceEnd() {
268 protected String tabString(int tab) {
269 StringBuffer result = new StringBuffer();
270 for (int i = tab; i > 0; i--) {
271 result.append(" "); //$NON-NLS-1$
273 return result.toString();
277 * Answer the top node
279 public RecoveredElement topElement() {
280 RecoveredElement current = this;
281 while (current.parent != null) {
282 current = current.parent;
287 public String toString() {
291 public String toString(int tab) {
292 return super.toString();
296 * Answer the enclosing type node, or null if none
298 // public RecoveredType type(){
299 // RecoveredElement current = this;
300 // while (current != null){
301 // if (current instanceof RecoveredType){
302 // return (RecoveredType) current;
304 // current = current.parent;
309 * Update the bodyStart of the corresponding parse node
311 public void updateBodyStart(int bodyStart) {
312 this.foundOpeningBrace = true;
316 * Update the corresponding parse node from parser state which is about to
317 * disappear because of restarting recovery
319 public void updateFromParserState() {
323 * A closing brace got consumed, might have closed the current element, in
324 * which case both the currentElement is exited
326 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd) {
327 if ((--bracketBalance <= 0) && (parent != null)) {
328 this.updateSourceEndIfNecessary(braceEnd);
335 * An opening brace got consumed, might be the expected opening one of the
336 * current element, in which case the bodyStart is updated.
338 public RecoveredElement updateOnOpeningBrace(int braceEnd) {
340 if (bracketBalance++ == 0) {
341 this.updateBodyStart(braceEnd + 1);
344 return null; // no update is necessary
348 * Final update the corresponding parse node
350 public void updateParseTree() {
354 * Update the declarationSourceEnd of the corresponding parse node
356 public void updateSourceEndIfNecessary(int sourceEnd) {