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