src/share/classes/com/sun/tools/javac/parser/DocCommentScanner.java

Fri, 29 Aug 2008 11:10:12 -0700

author
jjg
date
Fri, 29 Aug 2008 11:10:12 -0700
changeset 104
5e89c4ca637c
parent 1
9a66ca7c79fa
child 117
24a47c3062fe
permissions
-rw-r--r--

6597471: unused imports in javax.tools.JavaCompiler
6597531: unused imports and unused private const. in com.sun.tools.javac.Server.java
Reviewed-by: mcimadamore
Contributed-by: davide.angelocola@gmail.com

duke@1 1 /*
duke@1 2 * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved.
duke@1 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1 4 *
duke@1 5 * This code is free software; you can redistribute it and/or modify it
duke@1 6 * under the terms of the GNU General Public License version 2 only, as
duke@1 7 * published by the Free Software Foundation. Sun designates this
duke@1 8 * particular file as subject to the "Classpath" exception as provided
duke@1 9 * by Sun in the LICENSE file that accompanied this code.
duke@1 10 *
duke@1 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@1 15 * accompanied this code).
duke@1 16 *
duke@1 17 * You should have received a copy of the GNU General Public License version
duke@1 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@1 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1 20 *
duke@1 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@1 22 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@1 23 * have any questions.
duke@1 24 */
duke@1 25
duke@1 26 package com.sun.tools.javac.parser;
duke@1 27
duke@1 28 import java.nio.*;
duke@1 29
duke@1 30 import com.sun.tools.javac.util.*;
duke@1 31 import static com.sun.tools.javac.util.LayoutCharacters.*;
duke@1 32
duke@1 33 /** An extension to the base lexical analyzer that captures
duke@1 34 * and processes the contents of doc comments. It does so by
duke@1 35 * translating Unicode escape sequences and by stripping the
duke@1 36 * leading whitespace and starts from each line of the comment.
duke@1 37 *
duke@1 38 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
duke@1 39 * you write code that depends on this, you do so at your own risk.
duke@1 40 * This code and its internal interfaces are subject to change or
duke@1 41 * deletion without notice.</b>
duke@1 42 */
duke@1 43 public class DocCommentScanner extends Scanner {
duke@1 44
duke@1 45 /** A factory for creating scanners. */
duke@1 46 public static class Factory extends Scanner.Factory {
duke@1 47
duke@1 48 public static void preRegister(final Context context) {
duke@1 49 context.put(scannerFactoryKey, new Context.Factory<Scanner.Factory>() {
duke@1 50 public Factory make() {
duke@1 51 return new Factory(context);
duke@1 52 }
duke@1 53 });
duke@1 54 }
duke@1 55
duke@1 56 /** Create a new scanner factory. */
duke@1 57 protected Factory(Context context) {
duke@1 58 super(context);
duke@1 59 }
duke@1 60
duke@1 61 @Override
duke@1 62 public Scanner newScanner(CharSequence input) {
duke@1 63 if (input instanceof CharBuffer) {
duke@1 64 return new DocCommentScanner(this, (CharBuffer)input);
duke@1 65 } else {
duke@1 66 char[] array = input.toString().toCharArray();
duke@1 67 return newScanner(array, array.length);
duke@1 68 }
duke@1 69 }
duke@1 70
duke@1 71 @Override
duke@1 72 public Scanner newScanner(char[] input, int inputLength) {
duke@1 73 return new DocCommentScanner(this, input, inputLength);
duke@1 74 }
duke@1 75 }
duke@1 76
duke@1 77
duke@1 78 /** Create a scanner from the input buffer. buffer must implement
duke@1 79 * array() and compact(), and remaining() must be less than limit().
duke@1 80 */
duke@1 81 protected DocCommentScanner(Factory fac, CharBuffer buffer) {
duke@1 82 super(fac, buffer);
duke@1 83 }
duke@1 84
duke@1 85 /** Create a scanner from the input array. The array must have at
duke@1 86 * least a single character of extra space.
duke@1 87 */
duke@1 88 protected DocCommentScanner(Factory fac, char[] input, int inputLength) {
duke@1 89 super(fac, input, inputLength);
duke@1 90 }
duke@1 91
duke@1 92 /** Starting position of the comment in original source
duke@1 93 */
duke@1 94 private int pos;
duke@1 95
duke@1 96 /** The comment input buffer, index of next chacter to be read,
duke@1 97 * index of one past last character in buffer.
duke@1 98 */
duke@1 99 private char[] buf;
duke@1 100 private int bp;
duke@1 101 private int buflen;
duke@1 102
duke@1 103 /** The current character.
duke@1 104 */
duke@1 105 private char ch;
duke@1 106
duke@1 107 /** The column number position of the current character.
duke@1 108 */
duke@1 109 private int col;
duke@1 110
duke@1 111 /** The buffer index of the last converted Unicode character
duke@1 112 */
duke@1 113 private int unicodeConversionBp = 0;
duke@1 114
duke@1 115 /**
duke@1 116 * Buffer for doc comment.
duke@1 117 */
duke@1 118 private char[] docCommentBuffer = new char[1024];
duke@1 119
duke@1 120 /**
duke@1 121 * Number of characters in doc comment buffer.
duke@1 122 */
duke@1 123 private int docCommentCount;
duke@1 124
duke@1 125 /**
duke@1 126 * Translated and stripped contents of doc comment
duke@1 127 */
duke@1 128 private String docComment = null;
duke@1 129
duke@1 130
duke@1 131 /** Unconditionally expand the comment buffer.
duke@1 132 */
duke@1 133 private void expandCommentBuffer() {
duke@1 134 char[] newBuffer = new char[docCommentBuffer.length * 2];
duke@1 135 System.arraycopy(docCommentBuffer, 0, newBuffer,
duke@1 136 0, docCommentBuffer.length);
duke@1 137 docCommentBuffer = newBuffer;
duke@1 138 }
duke@1 139
duke@1 140 /** Convert an ASCII digit from its base (8, 10, or 16)
duke@1 141 * to its value.
duke@1 142 */
duke@1 143 private int digit(int base) {
duke@1 144 char c = ch;
duke@1 145 int result = Character.digit(c, base);
duke@1 146 if (result >= 0 && c > 0x7f) {
duke@1 147 ch = "0123456789abcdef".charAt(result);
duke@1 148 }
duke@1 149 return result;
duke@1 150 }
duke@1 151
duke@1 152 /** Convert Unicode escape; bp points to initial '\' character
duke@1 153 * (Spec 3.3).
duke@1 154 */
duke@1 155 private void convertUnicode() {
duke@1 156 if (ch == '\\' && unicodeConversionBp != bp) {
duke@1 157 bp++; ch = buf[bp]; col++;
duke@1 158 if (ch == 'u') {
duke@1 159 do {
duke@1 160 bp++; ch = buf[bp]; col++;
duke@1 161 } while (ch == 'u');
duke@1 162 int limit = bp + 3;
duke@1 163 if (limit < buflen) {
duke@1 164 int d = digit(16);
duke@1 165 int code = d;
duke@1 166 while (bp < limit && d >= 0) {
duke@1 167 bp++; ch = buf[bp]; col++;
duke@1 168 d = digit(16);
duke@1 169 code = (code << 4) + d;
duke@1 170 }
duke@1 171 if (d >= 0) {
duke@1 172 ch = (char)code;
duke@1 173 unicodeConversionBp = bp;
duke@1 174 return;
duke@1 175 }
duke@1 176 }
duke@1 177 // "illegal.Unicode.esc", reported by base scanner
duke@1 178 } else {
duke@1 179 bp--;
duke@1 180 ch = '\\';
duke@1 181 col--;
duke@1 182 }
duke@1 183 }
duke@1 184 }
duke@1 185
duke@1 186
duke@1 187 /** Read next character.
duke@1 188 */
duke@1 189 private void scanChar() {
duke@1 190 bp++;
duke@1 191 ch = buf[bp];
duke@1 192 switch (ch) {
duke@1 193 case '\r': // return
duke@1 194 col = 0;
duke@1 195 break;
duke@1 196 case '\n': // newline
duke@1 197 if (bp == 0 || buf[bp-1] != '\r') {
duke@1 198 col = 0;
duke@1 199 }
duke@1 200 break;
duke@1 201 case '\t': // tab
duke@1 202 col = (col / TabInc * TabInc) + TabInc;
duke@1 203 break;
duke@1 204 case '\\': // possible Unicode
duke@1 205 col++;
duke@1 206 convertUnicode();
duke@1 207 break;
duke@1 208 default:
duke@1 209 col++;
duke@1 210 break;
duke@1 211 }
duke@1 212 }
duke@1 213
duke@1 214 /**
duke@1 215 * Read next character in doc comment, skipping over double '\' characters.
duke@1 216 * If a double '\' is skipped, put in the buffer and update buffer count.
duke@1 217 */
duke@1 218 private void scanDocCommentChar() {
duke@1 219 scanChar();
duke@1 220 if (ch == '\\') {
duke@1 221 if (buf[bp+1] == '\\' && unicodeConversionBp != bp) {
duke@1 222 if (docCommentCount == docCommentBuffer.length)
duke@1 223 expandCommentBuffer();
duke@1 224 docCommentBuffer[docCommentCount++] = ch;
duke@1 225 bp++; col++;
duke@1 226 } else {
duke@1 227 convertUnicode();
duke@1 228 }
duke@1 229 }
duke@1 230 }
duke@1 231
duke@1 232 /* Reset doc comment before reading each new token
duke@1 233 */
duke@1 234 public void nextToken() {
duke@1 235 docComment = null;
duke@1 236 super.nextToken();
duke@1 237 }
duke@1 238
duke@1 239 /**
duke@1 240 * Returns the documentation string of the current token.
duke@1 241 */
duke@1 242 public String docComment() {
duke@1 243 return docComment;
duke@1 244 }
duke@1 245
duke@1 246 /**
duke@1 247 * Process a doc comment and make the string content available.
duke@1 248 * Strips leading whitespace and stars.
duke@1 249 */
duke@1 250 @SuppressWarnings("fallthrough")
duke@1 251 protected void processComment(CommentStyle style) {
duke@1 252 if (style != CommentStyle.JAVADOC) {
duke@1 253 return;
duke@1 254 }
duke@1 255
duke@1 256 pos = pos();
duke@1 257 buf = getRawCharacters(pos, endPos());
duke@1 258 buflen = buf.length;
duke@1 259 bp = 0;
duke@1 260 col = 0;
duke@1 261
duke@1 262 docCommentCount = 0;
duke@1 263
duke@1 264 boolean firstLine = true;
duke@1 265
duke@1 266 // Skip over first slash
duke@1 267 scanDocCommentChar();
duke@1 268 // Skip over first star
duke@1 269 scanDocCommentChar();
duke@1 270
duke@1 271 // consume any number of stars
duke@1 272 while (bp < buflen && ch == '*') {
duke@1 273 scanDocCommentChar();
duke@1 274 }
duke@1 275 // is the comment in the form /**/, /***/, /****/, etc. ?
duke@1 276 if (bp < buflen && ch == '/') {
duke@1 277 docComment = "";
duke@1 278 return;
duke@1 279 }
duke@1 280
duke@1 281 // skip a newline on the first line of the comment.
duke@1 282 if (bp < buflen) {
duke@1 283 if (ch == LF) {
duke@1 284 scanDocCommentChar();
duke@1 285 firstLine = false;
duke@1 286 } else if (ch == CR) {
duke@1 287 scanDocCommentChar();
duke@1 288 if (ch == LF) {
duke@1 289 scanDocCommentChar();
duke@1 290 firstLine = false;
duke@1 291 }
duke@1 292 }
duke@1 293 }
duke@1 294
duke@1 295 outerLoop:
duke@1 296
duke@1 297 // The outerLoop processes the doc comment, looping once
duke@1 298 // for each line. For each line, it first strips off
duke@1 299 // whitespace, then it consumes any stars, then it
duke@1 300 // puts the rest of the line into our buffer.
duke@1 301 while (bp < buflen) {
duke@1 302
duke@1 303 // The wsLoop consumes whitespace from the beginning
duke@1 304 // of each line.
duke@1 305 wsLoop:
duke@1 306
duke@1 307 while (bp < buflen) {
duke@1 308 switch(ch) {
duke@1 309 case ' ':
duke@1 310 scanDocCommentChar();
duke@1 311 break;
duke@1 312 case '\t':
duke@1 313 col = ((col - 1) / TabInc * TabInc) + TabInc;
duke@1 314 scanDocCommentChar();
duke@1 315 break;
duke@1 316 case FF:
duke@1 317 col = 0;
duke@1 318 scanDocCommentChar();
duke@1 319 break;
duke@1 320 // Treat newline at beginning of line (blank line, no star)
duke@1 321 // as comment text. Old Javadoc compatibility requires this.
duke@1 322 /*---------------------------------*
duke@1 323 case CR: // (Spec 3.4)
duke@1 324 scanDocCommentChar();
duke@1 325 if (ch == LF) {
duke@1 326 col = 0;
duke@1 327 scanDocCommentChar();
duke@1 328 }
duke@1 329 break;
duke@1 330 case LF: // (Spec 3.4)
duke@1 331 scanDocCommentChar();
duke@1 332 break;
duke@1 333 *---------------------------------*/
duke@1 334 default:
duke@1 335 // we've seen something that isn't whitespace;
duke@1 336 // jump out.
duke@1 337 break wsLoop;
duke@1 338 }
duke@1 339 }
duke@1 340
duke@1 341 // Are there stars here? If so, consume them all
duke@1 342 // and check for the end of comment.
duke@1 343 if (ch == '*') {
duke@1 344 // skip all of the stars
duke@1 345 do {
duke@1 346 scanDocCommentChar();
duke@1 347 } while (ch == '*');
duke@1 348
duke@1 349 // check for the closing slash.
duke@1 350 if (ch == '/') {
duke@1 351 // We're done with the doc comment
duke@1 352 // scanChar() and breakout.
duke@1 353 break outerLoop;
duke@1 354 }
duke@1 355 } else if (! firstLine) {
duke@1 356 //The current line does not begin with a '*' so we will indent it.
duke@1 357 for (int i = 1; i < col; i++) {
duke@1 358 if (docCommentCount == docCommentBuffer.length)
duke@1 359 expandCommentBuffer();
duke@1 360 docCommentBuffer[docCommentCount++] = ' ';
duke@1 361 }
duke@1 362 }
duke@1 363
duke@1 364 // The textLoop processes the rest of the characters
duke@1 365 // on the line, adding them to our buffer.
duke@1 366 textLoop:
duke@1 367 while (bp < buflen) {
duke@1 368 switch (ch) {
duke@1 369 case '*':
duke@1 370 // Is this just a star? Or is this the
duke@1 371 // end of a comment?
duke@1 372 scanDocCommentChar();
duke@1 373 if (ch == '/') {
duke@1 374 // This is the end of the comment,
duke@1 375 // set ch and return our buffer.
duke@1 376 break outerLoop;
duke@1 377 }
duke@1 378 // This is just an ordinary star. Add it to
duke@1 379 // the buffer.
duke@1 380 if (docCommentCount == docCommentBuffer.length)
duke@1 381 expandCommentBuffer();
duke@1 382 docCommentBuffer[docCommentCount++] = '*';
duke@1 383 break;
duke@1 384 case ' ':
duke@1 385 case '\t':
duke@1 386 if (docCommentCount == docCommentBuffer.length)
duke@1 387 expandCommentBuffer();
duke@1 388 docCommentBuffer[docCommentCount++] = ch;
duke@1 389 scanDocCommentChar();
duke@1 390 break;
duke@1 391 case FF:
duke@1 392 scanDocCommentChar();
duke@1 393 break textLoop; // treat as end of line
duke@1 394 case CR: // (Spec 3.4)
duke@1 395 scanDocCommentChar();
duke@1 396 if (ch != LF) {
duke@1 397 // Canonicalize CR-only line terminator to LF
duke@1 398 if (docCommentCount == docCommentBuffer.length)
duke@1 399 expandCommentBuffer();
duke@1 400 docCommentBuffer[docCommentCount++] = (char)LF;
duke@1 401 break textLoop;
duke@1 402 }
duke@1 403 /* fall through to LF case */
duke@1 404 case LF: // (Spec 3.4)
duke@1 405 // We've seen a newline. Add it to our
duke@1 406 // buffer and break out of this loop,
duke@1 407 // starting fresh on a new line.
duke@1 408 if (docCommentCount == docCommentBuffer.length)
duke@1 409 expandCommentBuffer();
duke@1 410 docCommentBuffer[docCommentCount++] = ch;
duke@1 411 scanDocCommentChar();
duke@1 412 break textLoop;
duke@1 413 default:
duke@1 414 // Add the character to our buffer.
duke@1 415 if (docCommentCount == docCommentBuffer.length)
duke@1 416 expandCommentBuffer();
duke@1 417 docCommentBuffer[docCommentCount++] = ch;
duke@1 418 scanDocCommentChar();
duke@1 419 }
duke@1 420 } // end textLoop
duke@1 421 firstLine = false;
duke@1 422 } // end outerLoop
duke@1 423
duke@1 424 if (docCommentCount > 0) {
duke@1 425 int i = docCommentCount - 1;
duke@1 426 trailLoop:
duke@1 427 while (i > -1) {
duke@1 428 switch (docCommentBuffer[i]) {
duke@1 429 case '*':
duke@1 430 i--;
duke@1 431 break;
duke@1 432 default:
duke@1 433 break trailLoop;
duke@1 434 }
duke@1 435 }
duke@1 436 docCommentCount = i + 1;
duke@1 437
duke@1 438 // Store the text of the doc comment
duke@1 439 docComment = new String(docCommentBuffer, 0 , docCommentCount);
duke@1 440 } else {
duke@1 441 docComment = "";
duke@1 442 }
duke@1 443 }
duke@1 444
duke@1 445 /** Build a map for translating between line numbers and
duke@1 446 * positions in the input.
duke@1 447 *
duke@1 448 * @return a LineMap */
duke@1 449 public Position.LineMap getLineMap() {
duke@1 450 char[] buf = getRawCharacters();
duke@1 451 return Position.makeLineMap(buf, buf.length, true);
duke@1 452 }
duke@1 453 }

mercurial