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.FieldDeclaration;
16 import net.sourceforge.phpeclipse.internal.compiler.ast.Statement;
19 * Internal structure for parsing recovery
22 public class RecoveredElement {
24 public RecoveredElement parent;
25 public int bracketBalance;
26 public boolean foundOpeningBrace;
27 protected Parser recoveringParser;
28 public RecoveredElement(RecoveredElement parent, int bracketBalance){
29 this(parent, bracketBalance, null);
31 public RecoveredElement(RecoveredElement parent, int bracketBalance, Parser parser){
33 this.bracketBalance = bracketBalance;
34 this.recoveringParser = parser;
37 * Record a method declaration
39 //public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalance) {
41 // /* default behavior is to delegate recording to parent if any */
42 // if (parent == null) {
43 // return this; // ignore
45 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(methodDeclaration.declarationSourceStart - 1));
46 // return this.parent.add(methodDeclaration, bracketBalance);
50 * Record a nested block declaration
52 public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) {
54 /* default behavior is to delegate recording to parent if any */
56 return this; // ignore
58 this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(nestedBlockDeclaration.sourceStart - 1));
59 return this.parent.add(nestedBlockDeclaration, bracketBalance);
63 * Record a field declaration
65 //public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalance) {
67 // /* default behavior is to delegate recording to parent if any */
68 // if (parent == null) {
69 // return this; // ignore
71 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1));
72 // return this.parent.add(fieldDeclaration, bracketBalance);
76 // * Record an import reference
78 //public RecoveredElement add(ImportReference importReference, int bracketBalance){
80 // /* default behavior is to delegate recording to parent if any */
81 // if (parent == null) {
82 // return this; // ignore
84 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(importReference.declarationSourceStart - 1));
85 // return this.parent.add(importReference, bracketBalance);
89 // * Record a local declaration
91 //public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalance) {
93 // /* default behavior is to delegate recording to parent if any */
94 // if (parent == null) {
95 // return this; // ignore
97 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1));
98 // return this.parent.add(localDeclaration, bracketBalance);
104 public RecoveredElement add(Statement statement, int bracketBalance) {
106 /* default behavior is to delegate recording to parent if any */
107 if (parent == null) {
108 return this; // ignore
110 this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(statement.sourceStart - 1));
111 return this.parent.add(statement, bracketBalance);
115 * Record a type declaration
117 //public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance){
119 // /* default behavior is to delegate recording to parent if any */
120 // if (parent == null) {
121 // return this; // ignore
123 // this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1));
124 // return this.parent.add(typeDeclaration, bracketBalance);
128 * Answer the depth of this element, considering the parent link.
132 RecoveredElement current = this;
133 while ((current = current.parent) != null) depth++;
137 * Answer the enclosing method node, or null if none
139 //public RecoveredInitializer enclosingInitializer(){
140 // RecoveredElement current = this;
141 // while (current != null){
142 // if (current instanceof RecoveredInitializer){
143 // return (RecoveredInitializer) current;
145 // current = current.parent;
150 * Answer the enclosing method node, or null if none
152 //public RecoveredMethod enclosingMethod(){
153 // RecoveredElement current = this;
154 // while (current != null){
155 // if (current instanceof RecoveredMethod){
156 // return (RecoveredMethod) current;
158 // current = current.parent;
163 * Answer the enclosing type node, or null if none
165 //public RecoveredType enclosingType(){
166 // RecoveredElement current = this;
167 // while (current != null){
168 // if (current instanceof RecoveredType){
169 // return (RecoveredType) current;
171 // current = current.parent;
176 * Answer the closest specified parser
178 public Parser parser(){
179 RecoveredElement current = this;
180 while (current != null){
181 if (current.recoveringParser != null){
182 return current.recoveringParser;
184 current = current.parent;
189 * Answer the associated parsed structure
191 public AstNode parseTree(){
195 * Iterate the enclosing blocks and tag them so as to preserve their content
197 //public void preserveEnclosingBlocks(){
198 // RecoveredElement current = this;
199 // while (current != null){
200 // if (current instanceof RecoveredBlock){
201 // ((RecoveredBlock)current).preserveContent = true;
203 // if (current instanceof RecoveredType){ // for anonymous types
204 // ((RecoveredType)current).preserveContent = true;
206 // current = current.parent;
210 * Answer the position of the previous line end if
211 * there is nothing but spaces in between it and the
212 * line end. Used to trim spaces on unclosed elements.
214 public int previousAvailableLineEnd(int position){
216 Parser parser = this.parser();
217 if (parser == null) return position;
219 Scanner scanner = parser.scanner;
220 if (scanner.lineEnds == null) return position;
222 int index = scanner.getLineNumber(position);
223 if (index < 2) return position;
224 int previousLineEnd = scanner.lineEnds[index-2];
226 char[] source = scanner.source;
227 for (int i = previousLineEnd+1; i < position; i++){
228 if (!(source[i] == ' ' || source[i] == '\t')) return position;
230 return previousLineEnd;
233 * Answer the very source end of the corresponding parse node
235 public int sourceEnd(){
238 protected String tabString(int tab) {
239 StringBuffer result = new StringBuffer();
240 for (int i = tab; i > 0; i--) {
241 result.append(" "); //$NON-NLS-1$
243 return result.toString();
246 * Answer the top node
248 public RecoveredElement topElement(){
249 RecoveredElement current = this;
250 while (current.parent != null){
251 current = current.parent;
255 public String toString() {
258 public String toString(int tab) {
259 return super.toString();
262 * Answer the enclosing type node, or null if none
264 //public RecoveredType type(){
265 // RecoveredElement current = this;
266 // while (current != null){
267 // if (current instanceof RecoveredType){
268 // return (RecoveredType) current;
270 // current = current.parent;
275 * Update the bodyStart of the corresponding parse node
277 public void updateBodyStart(int bodyStart){
278 this.foundOpeningBrace = true;
281 * Update the corresponding parse node from parser state which
282 * is about to disappear because of restarting recovery
284 public void updateFromParserState(){
287 * A closing brace got consumed, might have closed the current element,
288 * in which case both the currentElement is exited
290 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
291 if ((--bracketBalance <= 0) && (parent != null)){
292 this.updateSourceEndIfNecessary(braceEnd);
298 * An opening brace got consumed, might be the expected opening one of the current element,
299 * in which case the bodyStart is updated.
301 public RecoveredElement updateOnOpeningBrace(int braceEnd){
303 if (bracketBalance++ == 0){
304 this.updateBodyStart(braceEnd + 1);
307 return null; // no update is necessary
310 * Final update the corresponding parse node
312 public void updateParseTree(){
315 * Update the declarationSourceEnd of the corresponding parse node
317 public void updateSourceEndIfNecessary(int sourceEnd){