d0cf93d2874bcb2af04cdf5fa7a2c8539e2f9c5c
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / util / CommentRecorderParser.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core.util;
12
13 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
14 import net.sourceforge.phpdt.internal.compiler.parser.UnitParser;
15 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
16 import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities;
17 import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration;
18
19 /**
20  * Internal parser used for parsing source to create DOM AST nodes.
21  * 
22  * @since 3.0
23  */
24 public class CommentRecorderParser extends UnitParser {
25         
26         // support for comments
27         int[] commentStops = new int[10];
28         int[] commentStarts = new int[10];
29         int commentPtr = -1; // no comment test with commentPtr value -1
30         protected final static int CommentIncrement = 100;
31
32         /**
33          * @param problemReporter
34          * @param optimizeStringLiterals
35          */
36         public CommentRecorderParser(ProblemReporter problemReporter) { // , boolean optimizeStringLiterals) {
37                 super(problemReporter); //, optimizeStringLiterals);
38         }
39
40         // old javadoc style check which doesn't include all leading comments into declaration
41         // for backward compatibility with 2.1 DOM 
42 //      public void checkComment() {
43 //
44 //              if (this.currentElement != null && this.scanner.commentPtr >= 0) {
45 //                      flushCommentsDefinedPriorTo(this.endStatementPosition); // discard obsolete comments
46 //              }
47 //              boolean deprecated = false;
48 //              boolean checkDeprecated = false;
49 //              int lastCommentIndex = -1;
50 //              
51 //              // 
52 //              
53 //              //since jdk1.2 look only in the last java doc comment...
54 //              nextComment : for (lastCommentIndex = this.scanner.commentPtr; lastCommentIndex >= 0; lastCommentIndex--){
55 //                      //look for @deprecated into the first javadoc comment preceeding the declaration
56 //                      int commentSourceStart = this.scanner.commentStarts[lastCommentIndex];
57 //                      // javadoc only (non javadoc comment have negative end positions.)
58 //                      if ((commentSourceStart < 0) ||
59 //                              (this.modifiersSourceStart != -1 && this.modifiersSourceStart < commentSourceStart) ||
60 //                              (this.scanner.commentStops[lastCommentIndex] < 0))
61 //                      {
62 //                              continue nextComment;
63 //                      }
64 //                      checkDeprecated = true;
65 //                      int commentSourceEnd = this.scanner.commentStops[lastCommentIndex] - 1; //stop is one over
66 //                      
67 //                      deprecated = this.javadocParser.checkDeprecation(commentSourceStart, commentSourceEnd);
68 //                      this.javadoc = this.javadocParser.docComment;
69 //                      break nextComment;
70 //              }
71 //              if (deprecated) {
72 //                      checkAndSetModifiers(AccDeprecated);
73 //              }
74 //              // modify the modifier source start to point at the first comment
75 //              if (lastCommentIndex >= 0 && checkDeprecated) {
76 //                      this.modifiersSourceStart = this.scanner.commentStarts[lastCommentIndex]; 
77 //                      if (this.modifiersSourceStart < 0) {
78 //                              this.modifiersSourceStart = -this.modifiersSourceStart;
79 //                      }
80 //              }
81 //
82 //      }
83
84 //      /* (non-Javadoc)
85 //       * @see org.eclipse.jdt.internal.compiler.parser.Parser#consumeClassHeader()
86 //       */
87 //      protected void consumeClassHeader() {
88 //              pushOnCommentsStack(0, this.scanner.commentPtr);
89 //              super.consumeClassHeader();
90 //      }
91 //      /* (non-Javadoc)
92 //       * @see org.eclipse.jdt.internal.compiler.parser.Parser#consumeEmptyClassMemberDeclaration()
93 //       */
94 //      protected void consumeEmptyClassMemberDeclaration() {
95 //              pushOnCommentsStack(0, this.scanner.commentPtr);
96 //              super.consumeEmptyClassMemberDeclaration();
97 //      }
98 //      /* (non-Javadoc)
99 //       * @see org.eclipse.jdt.internal.compiler.parser.Parser#consumeEmptyTypeDeclaration()
100 //       */
101 //      protected void consumeEmptyTypeDeclaration() {
102 //              pushOnCommentsStack(0, this.scanner.commentPtr);
103 //              super.consumeEmptyTypeDeclaration();
104 //      }
105 //      /* (non-Javadoc)
106 //       * @see org.eclipse.jdt.internal.compiler.parser.Parser#consumeInterfaceHeader()
107 //       */
108 //      protected void consumeInterfaceHeader() {
109 //              pushOnCommentsStack(0, this.scanner.commentPtr);
110 //              super.consumeInterfaceHeader();
111 //      }
112
113         /**
114          * Insure that start position is always positive.
115          * @see org.eclipse.jdt.internal.compiler.parser.Parser#containsComment(int, int)
116          */
117         public boolean containsComment(int sourceStart, int sourceEnd) {
118                 int iComment = this.scanner.commentPtr;
119                 for (; iComment >= 0; iComment--) {
120                         int commentStart = this.scanner.commentStarts[iComment];
121                         if (commentStart < 0) {
122                                 commentStart = -commentStart;
123                         }
124                         // ignore comments before start
125                         if (commentStart < sourceStart) continue;
126                         // ignore comments after end
127                         if (commentStart > sourceEnd) continue;
128                         return true;
129                 }
130                 return false;
131         }
132
133         /* (non-Javadoc)
134          * @see org.eclipse.jdt.internal.compiler.parser.Parser#endParse(int)
135          */
136         protected CompilationUnitDeclaration endParse(int act) {
137                 CompilationUnitDeclaration unit = super.endParse(act);
138                 if (unit.comments == null) {
139                         pushOnCommentsStack(0, this.scanner.commentPtr);
140                         unit.comments = getCommentsPositions();
141                 }
142                 return unit;
143         }
144
145         /* (non-Javadoc)
146          * Save all source comments currently stored before flushing them.
147          * @see org.eclipse.jdt.internal.compiler.parser.Parser#flushCommentsDefinedPriorTo(int)
148          */
149         public int flushCommentsDefinedPriorTo(int position) {
150
151                 int lastCommentIndex = this.scanner.commentPtr;
152                 if (lastCommentIndex < 0) return position; // no comment
153         
154                 // compute the index of the first obsolete comment
155                 int index = lastCommentIndex;
156                 int validCount = 0;
157                 while (index >= 0){
158                         int commentEnd = this.scanner.commentStops[index];
159                         if (commentEnd < 0) commentEnd = -commentEnd; // negative end position for non-javadoc comments
160                         if (commentEnd <= position){
161                                 break;
162                         }
163                         index--;
164                         validCount++;
165                 }
166                 // if the source at <position> is immediately followed by a line comment, then
167                 // flush this comment and shift <position> to the comment end.
168                 if (validCount > 0){
169                         int immediateCommentEnd = 0;
170                         while (index<lastCommentIndex && (immediateCommentEnd = -this.scanner.commentStops[index+1])  > 0){ // only tolerating non-javadoc comments (non-javadoc comment end positions are negative)
171                                 // is there any line break until the end of the immediate comment ? (thus only tolerating line comment)
172                                 immediateCommentEnd--; // comment end in one char too far
173                                 if (this.scanner.getLineNumber(position) != this.scanner.getLineNumber(immediateCommentEnd)) break;
174                                 position = immediateCommentEnd;
175                                 validCount--; // flush this comment
176                                 index++;
177                         }
178                 }
179         
180                 if (index < 0) return position; // no obsolete comment
181                 pushOnCommentsStack(0, index); // store comment before flushing them
182
183                 if (validCount > 0){ // move valid comment infos, overriding obsolete comment infos
184                         System.arraycopy(this.scanner.commentStarts, index + 1, this.scanner.commentStarts, 0, validCount);
185                         System.arraycopy(this.scanner.commentStops, index + 1, this.scanner.commentStops, 0, validCount);               
186                 }
187                 this.scanner.commentPtr = validCount - 1;
188                 return position;
189         }
190
191         /*
192          * Build a n*2 matrix of comments positions.
193          * For each position, 0 is for start position and 1 for end position of the comment.
194          */
195         public int[][] getCommentsPositions() {
196                 int[][] positions = new int[this.commentPtr+1][2];
197                 for (int i = 0, max = this.commentPtr; i <= max; i++){
198                         positions[i][0] = this.commentStarts[i];
199                         positions[i][1] = this.commentStops[i];
200                 }
201                 return positions;
202         }
203
204         /* (non-Javadoc)
205          * @see org.eclipse.jdt.internal.compiler.parser.Parser#initialize()
206          */
207         public void initialize(boolean phpMode) {
208                 super.initialize(phpMode);
209                 this.commentPtr = -1;
210         }
211         
212         /* (non-Javadoc)
213          * Create and store a specific comment recorder scanner.
214          * @see org.eclipse.jdt.internal.compiler.parser.Parser#initializeScanner()
215          */
216         public void initializeScanner() {
217                 this.scanner = new CommentRecorderScanner(
218                                 false /*comment*/, 
219                                 false /*whitespace*/, 
220                                 this.options.getSeverity(CompilerOptions.NonExternalizedString) != ProblemSeverities.Ignore /*nls*/, 
221 //                              this.options.sourceLevel /*sourceLevel*/, 
222                                 this.options.taskTags/*taskTags*/,
223                                 this.options.taskPriorites);/*taskPriorities*/
224 //                              this.options.isTaskCaseSensitive/*taskCaseSensitive*/);
225         }
226
227         /*
228          * Push all stored comments in stack.
229          */
230         private void pushOnCommentsStack(int start, int end) {
231         
232                 for (int i=start; i<=end; i++) {
233                         // First see if comment hasn't been already stored
234                         int scannerStart = this.scanner.commentStarts[i]<0 ? -this.scanner.commentStarts[i] : this.scanner.commentStarts[i];
235                         int commentStart = this.commentPtr == -1 ? -1 : (this.commentStarts[this.commentPtr]<0 ? -this.commentStarts[this.commentPtr] : this.commentStarts[this.commentPtr]);
236                         if (commentStart == -1 ||  scannerStart > commentStart) {
237                                 try {
238                                         this.commentPtr++;
239                                         this.commentStarts[this.commentPtr] = this.scanner.commentStarts[i];
240                                         this.commentStops[this.commentPtr] = this.scanner.commentStops[i];
241                                 } catch (IndexOutOfBoundsException e) {
242                                         // this.commentPtr is still correct 
243                                         int oldStackLength = this.commentStarts.length;
244                                         int oldCommentStarts[] = this.commentStarts;
245                                         this.commentStarts = new int[oldStackLength + CommentIncrement];
246                                         System.arraycopy(oldCommentStarts, 0, this.commentStarts, 0, oldStackLength);
247                                         this.commentStarts[this.commentPtr] = this.scanner.commentStarts[i];
248                                         int oldCommentStops[] = this.commentStops;
249                                         this.commentStops = new int[oldStackLength + CommentIncrement];
250                                         System.arraycopy(oldCommentStops, 0, this.commentStops, 0, oldStackLength);
251                                         this.commentStops[this.commentPtr] = this.scanner.commentStops[i];
252                                 }
253                         }
254                 }
255         }
256         /* (non-Javadoc)
257          * Save all source comments currently stored before flushing them.
258          * @see org.eclipse.jdt.internal.compiler.parser.Parser#resetModifiers()
259          */
260         protected void resetModifiers() {
261                 pushOnCommentsStack(0, this.scanner.commentPtr);
262                 super.resetModifiers();
263         }
264 }