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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core.util;
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;
20 * Internal parser used for parsing source to create DOM AST nodes.
24 public class CommentRecorderParser extends UnitParser {
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;
33 * @param problemReporter
34 * @param optimizeStringLiterals
36 public CommentRecorderParser(ProblemReporter problemReporter) { // , boolean optimizeStringLiterals) {
37 super(problemReporter); //, optimizeStringLiterals);
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() {
44 // if (this.currentElement != null && this.scanner.commentPtr >= 0) {
45 // flushCommentsDefinedPriorTo(this.endStatementPosition); // discard obsolete comments
47 // boolean deprecated = false;
48 // boolean checkDeprecated = false;
49 // int lastCommentIndex = -1;
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))
62 // continue nextComment;
64 // checkDeprecated = true;
65 // int commentSourceEnd = this.scanner.commentStops[lastCommentIndex] - 1; //stop is one over
67 // deprecated = this.javadocParser.checkDeprecation(commentSourceStart, commentSourceEnd);
68 // this.javadoc = this.javadocParser.docComment;
72 // checkAndSetModifiers(AccDeprecated);
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;
85 // * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#consumeClassHeader()
87 // protected void consumeClassHeader() {
88 // pushOnCommentsStack(0, this.scanner.commentPtr);
89 // super.consumeClassHeader();
92 // * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#consumeEmptyClassMemberDeclaration()
94 // protected void consumeEmptyClassMemberDeclaration() {
95 // pushOnCommentsStack(0, this.scanner.commentPtr);
96 // super.consumeEmptyClassMemberDeclaration();
99 // * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#consumeEmptyTypeDeclaration()
101 // protected void consumeEmptyTypeDeclaration() {
102 // pushOnCommentsStack(0, this.scanner.commentPtr);
103 // super.consumeEmptyTypeDeclaration();
106 // * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#consumeInterfaceHeader()
108 // protected void consumeInterfaceHeader() {
109 // pushOnCommentsStack(0, this.scanner.commentPtr);
110 // super.consumeInterfaceHeader();
114 * Insure that start position is always positive.
115 * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#containsComment(int, int)
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;
124 // ignore comments before start
125 if (commentStart < sourceStart) continue;
126 // ignore comments after end
127 if (commentStart > sourceEnd) continue;
134 * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#endParse(int)
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();
146 * Save all source comments currently stored before flushing them.
147 * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#flushCommentsDefinedPriorTo(int)
149 public int flushCommentsDefinedPriorTo(int position) {
151 int lastCommentIndex = this.scanner.commentPtr;
152 if (lastCommentIndex < 0) return position; // no comment
154 // compute the index of the first obsolete comment
155 int index = lastCommentIndex;
158 int commentEnd = this.scanner.commentStops[index];
159 if (commentEnd < 0) commentEnd = -commentEnd; // negative end position for non-javadoc comments
160 if (commentEnd <= position){
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.
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
180 if (index < 0) return position; // no obsolete comment
181 pushOnCommentsStack(0, index); // store comment before flushing them
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);
187 this.scanner.commentPtr = validCount - 1;
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.
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];
205 * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#initialize()
207 public void initialize(boolean phpMode) {
208 super.initialize(phpMode);
209 this.commentPtr = -1;
213 * Create and store a specific comment recorder scanner.
214 * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#initializeScanner()
216 public void initializeScanner() {
217 this.scanner = new CommentRecorderScanner(
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*/);
228 * Push all stored comments in stack.
230 private void pushOnCommentsStack(int start, int end) {
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) {
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];
257 * Save all source comments currently stored before flushing them.
258 * @see net.sourceforge.phpdt.internal.compiler.parser.Parser#resetModifiers()
260 protected void resetModifiers() {
261 pushOnCommentsStack(0, this.scanner.commentPtr);
262 super.resetModifiers();