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

Sun, 17 Feb 2013 16:44:55 -0500

author
dholmes
date
Sun, 17 Feb 2013 16:44:55 -0500
changeset 1571
af8417e590f4
parent 1529
950d8195a5a4
child 1679
b402b93cbe38
permissions
-rw-r--r--

Merge

mcimadamore@1113 1 /*
jjg@1529 2 * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
mcimadamore@1113 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
mcimadamore@1113 4 *
mcimadamore@1113 5 * This code is free software; you can redistribute it and/or modify it
mcimadamore@1113 6 * under the terms of the GNU General Public License version 2 only, as
mcimadamore@1113 7 * published by the Free Software Foundation. Oracle designates this
mcimadamore@1113 8 * particular file as subject to the "Classpath" exception as provided
mcimadamore@1113 9 * by Oracle in the LICENSE file that accompanied this code.
mcimadamore@1113 10 *
mcimadamore@1113 11 * This code is distributed in the hope that it will be useful, but WITHOUT
mcimadamore@1113 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
mcimadamore@1113 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
mcimadamore@1113 14 * version 2 for more details (a copy is included in the LICENSE file that
mcimadamore@1113 15 * accompanied this code).
mcimadamore@1113 16 *
mcimadamore@1113 17 * You should have received a copy of the GNU General Public License version
mcimadamore@1113 18 * 2 along with this work; if not, write to the Free Software Foundation,
mcimadamore@1113 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
mcimadamore@1113 20 *
mcimadamore@1113 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
mcimadamore@1113 22 * or visit www.oracle.com if you need additional information or have any
mcimadamore@1113 23 * questions.
mcimadamore@1113 24 */
mcimadamore@1113 25
mcimadamore@1113 26 package com.sun.tools.javac.parser;
mcimadamore@1113 27
mcimadamore@1125 28 import com.sun.tools.javac.parser.Tokens.Comment;
mcimadamore@1125 29 import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
mcimadamore@1113 30 import com.sun.tools.javac.util.*;
mcimadamore@1113 31
mcimadamore@1113 32 import java.nio.*;
mcimadamore@1113 33
mcimadamore@1113 34 import static com.sun.tools.javac.util.LayoutCharacters.*;
mcimadamore@1113 35
mcimadamore@1113 36 /** An extension to the base lexical analyzer that captures
mcimadamore@1113 37 * and processes the contents of doc comments. It does so by
mcimadamore@1113 38 * translating Unicode escape sequences and by stripping the
mcimadamore@1113 39 * leading whitespace and starts from each line of the comment.
mcimadamore@1113 40 *
mcimadamore@1113 41 * <p><b>This is NOT part of any supported API.
mcimadamore@1113 42 * If you write code that depends on this, you do so at your own risk.
mcimadamore@1113 43 * This code and its internal interfaces are subject to change or
mcimadamore@1113 44 * deletion without notice.</b>
mcimadamore@1113 45 */
mcimadamore@1113 46 public class JavadocTokenizer extends JavaTokenizer {
mcimadamore@1113 47
mcimadamore@1113 48 /** Create a scanner from the input buffer. buffer must implement
mcimadamore@1113 49 * array() and compact(), and remaining() must be less than limit().
mcimadamore@1113 50 */
mcimadamore@1113 51 protected JavadocTokenizer(ScannerFactory fac, CharBuffer buffer) {
mcimadamore@1113 52 super(fac, buffer);
mcimadamore@1113 53 }
mcimadamore@1113 54
mcimadamore@1113 55 /** Create a scanner from the input array. The array must have at
mcimadamore@1113 56 * least a single character of extra space.
mcimadamore@1113 57 */
mcimadamore@1113 58 protected JavadocTokenizer(ScannerFactory fac, char[] input, int inputLength) {
mcimadamore@1113 59 super(fac, input, inputLength);
mcimadamore@1113 60 }
mcimadamore@1113 61
mcimadamore@1125 62 @Override
mcimadamore@1125 63 protected Comment processComment(int pos, int endPos, CommentStyle style) {
mcimadamore@1125 64 char[] buf = reader.getRawCharacters(pos, endPos);
jjg@1281 65 return new JavadocComment(new DocReader(fac, buf, buf.length, pos), style);
mcimadamore@1125 66 }
mcimadamore@1113 67
mcimadamore@1113 68 /**
mcimadamore@1125 69 * This is a specialized version of UnicodeReader that keeps track of the
jjg@1281 70 * column position within a given character stream (used for Javadoc processing),
jjg@1281 71 * and which builds a table for mapping positions in the comment string to
jjg@1281 72 * positions in the source file.
mcimadamore@1113 73 */
jjg@1281 74 static class DocReader extends UnicodeReader {
mcimadamore@1113 75
mcimadamore@1125 76 int col;
jjg@1281 77 int startPos;
mcimadamore@1113 78
jjg@1281 79 /**
jjg@1281 80 * A buffer for building a table for mapping positions in {@link #sbuf}
jjg@1281 81 * to positions in the source buffer.
jjg@1281 82 *
jjg@1281 83 * The array is organized as a series of pairs of integers: the first
jjg@1281 84 * number in each pair specifies a position in the comment text,
jjg@1281 85 * the second number in each pair specifies the corresponding position
jjg@1281 86 * in the source buffer. The pairs are sorted in ascending order.
jjg@1281 87 *
jjg@1281 88 * Since the mapping function is generally continuous, with successive
jjg@1281 89 * positions in the string corresponding to successive positions in the
jjg@1281 90 * source buffer, the table only needs to record discontinuities in
jjg@1281 91 * the mapping. The values of intermediate positions can be inferred.
jjg@1281 92 *
jjg@1281 93 * Discontinuities may occur in a number of places: when a newline
jjg@1281 94 * is followed by whitespace and asterisks (which are ignored),
jjg@1281 95 * when a tab is expanded into spaces, and when unicode escapes
jjg@1281 96 * are used in the source buffer.
jjg@1281 97 *
jjg@1281 98 * Thus, to find the source position of any position, p, in the comment
jjg@1281 99 * string, find the index, i, of the pair whose string offset
jjg@1281 100 * ({@code pbuf[i] }) is closest to but not greater than p. Then,
jjg@1281 101 * {@code sourcePos(p) = pbuf[i+1] + (p - pbuf[i]) }.
jjg@1281 102 */
jjg@1281 103 int[] pbuf = new int[128];
jjg@1281 104
jjg@1281 105 /**
jjg@1281 106 * The index of the next empty slot in the pbuf buffer.
jjg@1281 107 */
jjg@1281 108 int pp = 0;
jjg@1281 109
jjg@1281 110 DocReader(ScannerFactory fac, char[] input, int inputLength, int startPos) {
mcimadamore@1125 111 super(fac, input, inputLength);
jjg@1281 112 this.startPos = startPos;
mcimadamore@1125 113 }
mcimadamore@1113 114
mcimadamore@1125 115 @Override
mcimadamore@1125 116 protected void convertUnicode() {
mcimadamore@1125 117 if (ch == '\\' && unicodeConversionBp != bp) {
mcimadamore@1125 118 bp++; ch = buf[bp]; col++;
mcimadamore@1125 119 if (ch == 'u') {
mcimadamore@1125 120 do {
mcimadamore@1125 121 bp++; ch = buf[bp]; col++;
mcimadamore@1125 122 } while (ch == 'u');
mcimadamore@1125 123 int limit = bp + 3;
mcimadamore@1125 124 if (limit < buflen) {
mcimadamore@1125 125 int d = digit(bp, 16);
mcimadamore@1125 126 int code = d;
mcimadamore@1125 127 while (bp < limit && d >= 0) {
mcimadamore@1125 128 bp++; ch = buf[bp]; col++;
mcimadamore@1125 129 d = digit(bp, 16);
mcimadamore@1125 130 code = (code << 4) + d;
mcimadamore@1125 131 }
mcimadamore@1125 132 if (d >= 0) {
mcimadamore@1125 133 ch = (char)code;
mcimadamore@1125 134 unicodeConversionBp = bp;
mcimadamore@1125 135 return;
mcimadamore@1125 136 }
mcimadamore@1125 137 }
mcimadamore@1125 138 // "illegal.Unicode.esc", reported by base scanner
mcimadamore@1125 139 } else {
mcimadamore@1125 140 bp--;
mcimadamore@1125 141 ch = '\\';
mcimadamore@1125 142 col--;
mcimadamore@1125 143 }
mcimadamore@1125 144 }
mcimadamore@1125 145 }
mcimadamore@1113 146
mcimadamore@1125 147 @Override
mcimadamore@1125 148 protected void scanCommentChar() {
mcimadamore@1125 149 scanChar();
mcimadamore@1125 150 if (ch == '\\') {
mcimadamore@1125 151 if (peekChar() == '\\' && !isUnicode()) {
mcimadamore@1125 152 putChar(ch, false);
mcimadamore@1125 153 bp++; col++;
mcimadamore@1125 154 } else {
mcimadamore@1125 155 convertUnicode();
mcimadamore@1125 156 }
mcimadamore@1125 157 }
mcimadamore@1125 158 }
mcimadamore@1113 159
mcimadamore@1125 160 @Override
mcimadamore@1125 161 protected void scanChar() {
mcimadamore@1125 162 bp++;
mcimadamore@1125 163 ch = buf[bp];
mcimadamore@1125 164 switch (ch) {
mcimadamore@1125 165 case '\r': // return
mcimadamore@1125 166 col = 0;
mcimadamore@1125 167 break;
mcimadamore@1125 168 case '\n': // newline
mcimadamore@1125 169 if (bp == 0 || buf[bp-1] != '\r') {
mcimadamore@1125 170 col = 0;
mcimadamore@1125 171 }
mcimadamore@1125 172 break;
mcimadamore@1125 173 case '\t': // tab
mcimadamore@1125 174 col = (col / TabInc * TabInc) + TabInc;
mcimadamore@1125 175 break;
mcimadamore@1125 176 case '\\': // possible Unicode
mcimadamore@1125 177 col++;
mcimadamore@1125 178 convertUnicode();
mcimadamore@1125 179 break;
mcimadamore@1125 180 default:
mcimadamore@1125 181 col++;
mcimadamore@1125 182 break;
mcimadamore@1125 183 }
mcimadamore@1125 184 }
jjg@1281 185
jjg@1281 186 @Override
jjg@1281 187 public void putChar(char ch, boolean scan) {
jjg@1281 188 // At this point, bp is the position of the current character in buf,
jjg@1281 189 // and sp is the position in sbuf where this character will be put.
jjg@1281 190 // Record a new entry in pbuf if pbuf is empty or if sp and its
jjg@1281 191 // corresponding source position are not equidistant from the
jjg@1281 192 // corresponding values in the latest entry in the pbuf array.
jjg@1281 193 // (i.e. there is a discontinuity in the map function.)
jjg@1281 194 if ((pp == 0)
jjg@1281 195 || (sp - pbuf[pp - 2] != (startPos + bp) - pbuf[pp - 1])) {
jjg@1281 196 if (pp + 1 >= pbuf.length) {
jjg@1281 197 int[] new_pbuf = new int[pbuf.length * 2];
jjg@1281 198 System.arraycopy(pbuf, 0, new_pbuf, 0, pbuf.length);
jjg@1281 199 pbuf = new_pbuf;
jjg@1281 200 }
jjg@1281 201 pbuf[pp] = sp;
jjg@1281 202 pbuf[pp + 1] = startPos + bp;
jjg@1281 203 pp += 2;
jjg@1281 204 }
jjg@1281 205 super.putChar(ch, scan);
jjg@1281 206 }
mcimadamore@1125 207 }
mcimadamore@1125 208
jjg@1281 209 protected class JavadocComment extends JavaTokenizer.BasicComment<DocReader> {
mcimadamore@1125 210
mcimadamore@1125 211 /**
mcimadamore@1125 212 * Translated and stripped contents of doc comment
mcimadamore@1125 213 */
mcimadamore@1125 214 private String docComment = null;
jjg@1281 215 private int[] docPosns = null;
mcimadamore@1125 216
jjg@1281 217 JavadocComment(DocReader reader, CommentStyle cs) {
jjg@1281 218 super(reader, cs);
mcimadamore@1113 219 }
mcimadamore@1113 220
jjg@1281 221 @Override
mcimadamore@1125 222 public String getText() {
mcimadamore@1125 223 if (!scanned && cs == CommentStyle.JAVADOC) {
mcimadamore@1125 224 scanDocComment();
mcimadamore@1125 225 }
mcimadamore@1125 226 return docComment;
mcimadamore@1125 227 }
mcimadamore@1125 228
mcimadamore@1125 229 @Override
jjg@1281 230 public int getSourcePos(int pos) {
jjg@1281 231 // Binary search to find the entry for which the string index is
jjg@1281 232 // less than pos. Since docPosns is a list of pairs of integers
jjg@1281 233 // we must make sure the index is always even.
jjg@1281 234 // If we find an exact match for pos, the other item in the pair
jjg@1281 235 // gives the source pos; otherwise, compute the source position
jjg@1281 236 // relative to the best match found in the array.
jjg@1409 237 if (pos == Position.NOPOS)
jjg@1409 238 return Position.NOPOS;
jjg@1529 239 if (pos < 0 || pos > docComment.length())
jjg@1409 240 throw new StringIndexOutOfBoundsException(String.valueOf(pos));
jjg@1281 241 if (docPosns == null)
jjg@1409 242 return Position.NOPOS;
jjg@1281 243 int start = 0;
jjg@1281 244 int end = docPosns.length;
jjg@1281 245 while (start < end - 2) {
jjg@1281 246 // find an even index midway between start and end
jjg@1281 247 int index = ((start + end) / 4) * 2;
jjg@1281 248 if (docPosns[index] < pos)
jjg@1281 249 start = index;
jjg@1281 250 else if (docPosns[index] == pos)
jjg@1281 251 return docPosns[index + 1];
jjg@1281 252 else
jjg@1281 253 end = index;
jjg@1281 254 }
jjg@1281 255 return docPosns[start + 1] + (pos - docPosns[start]);
jjg@1281 256 }
jjg@1281 257
jjg@1281 258 @Override
mcimadamore@1125 259 @SuppressWarnings("fallthrough")
mcimadamore@1125 260 protected void scanDocComment() {
mcimadamore@1125 261 try {
mcimadamore@1125 262 boolean firstLine = true;
mcimadamore@1125 263
mcimadamore@1125 264 // Skip over first slash
mcimadamore@1125 265 comment_reader.scanCommentChar();
mcimadamore@1125 266 // Skip over first star
mcimadamore@1125 267 comment_reader.scanCommentChar();
mcimadamore@1125 268
mcimadamore@1125 269 // consume any number of stars
mcimadamore@1125 270 while (comment_reader.bp < comment_reader.buflen && comment_reader.ch == '*') {
mcimadamore@1125 271 comment_reader.scanCommentChar();
mcimadamore@1125 272 }
mcimadamore@1125 273 // is the comment in the form /**/, /***/, /****/, etc. ?
mcimadamore@1125 274 if (comment_reader.bp < comment_reader.buflen && comment_reader.ch == '/') {
mcimadamore@1125 275 docComment = "";
mcimadamore@1125 276 return;
mcimadamore@1125 277 }
mcimadamore@1125 278
mcimadamore@1125 279 // skip a newline on the first line of the comment.
mcimadamore@1125 280 if (comment_reader.bp < comment_reader.buflen) {
mcimadamore@1125 281 if (comment_reader.ch == LF) {
mcimadamore@1125 282 comment_reader.scanCommentChar();
mcimadamore@1125 283 firstLine = false;
mcimadamore@1125 284 } else if (comment_reader.ch == CR) {
mcimadamore@1125 285 comment_reader.scanCommentChar();
mcimadamore@1125 286 if (comment_reader.ch == LF) {
mcimadamore@1125 287 comment_reader.scanCommentChar();
mcimadamore@1125 288 firstLine = false;
mcimadamore@1125 289 }
mcimadamore@1125 290 }
mcimadamore@1125 291 }
mcimadamore@1125 292
mcimadamore@1125 293 outerLoop:
mcimadamore@1125 294
mcimadamore@1125 295 // The outerLoop processes the doc comment, looping once
mcimadamore@1125 296 // for each line. For each line, it first strips off
mcimadamore@1125 297 // whitespace, then it consumes any stars, then it
mcimadamore@1125 298 // puts the rest of the line into our buffer.
mcimadamore@1125 299 while (comment_reader.bp < comment_reader.buflen) {
jjg@1281 300 int begin_bp = comment_reader.bp;
jjg@1281 301 char begin_ch = comment_reader.ch;
mcimadamore@1125 302 // The wsLoop consumes whitespace from the beginning
mcimadamore@1125 303 // of each line.
mcimadamore@1125 304 wsLoop:
mcimadamore@1125 305
mcimadamore@1125 306 while (comment_reader.bp < comment_reader.buflen) {
mcimadamore@1125 307 switch(comment_reader.ch) {
mcimadamore@1125 308 case ' ':
mcimadamore@1125 309 comment_reader.scanCommentChar();
mcimadamore@1125 310 break;
mcimadamore@1125 311 case '\t':
mcimadamore@1125 312 comment_reader.col = ((comment_reader.col - 1) / TabInc * TabInc) + TabInc;
mcimadamore@1125 313 comment_reader.scanCommentChar();
mcimadamore@1125 314 break;
mcimadamore@1125 315 case FF:
mcimadamore@1125 316 comment_reader.col = 0;
mcimadamore@1125 317 comment_reader.scanCommentChar();
mcimadamore@1125 318 break;
mcimadamore@1125 319 // Treat newline at beginning of line (blank line, no star)
mcimadamore@1125 320 // as comment text. Old Javadoc compatibility requires this.
mcimadamore@1125 321 /*---------------------------------*
mcimadamore@1125 322 case CR: // (Spec 3.4)
mcimadamore@1125 323 doc_reader.scanCommentChar();
mcimadamore@1125 324 if (ch == LF) {
mcimadamore@1125 325 col = 0;
mcimadamore@1125 326 doc_reader.scanCommentChar();
mcimadamore@1125 327 }
mcimadamore@1125 328 break;
mcimadamore@1125 329 case LF: // (Spec 3.4)
mcimadamore@1125 330 doc_reader.scanCommentChar();
mcimadamore@1125 331 break;
mcimadamore@1125 332 *---------------------------------*/
mcimadamore@1125 333 default:
mcimadamore@1125 334 // we've seen something that isn't whitespace;
mcimadamore@1125 335 // jump out.
mcimadamore@1125 336 break wsLoop;
mcimadamore@1125 337 }
mcimadamore@1125 338 }
mcimadamore@1125 339
mcimadamore@1125 340 // Are there stars here? If so, consume them all
mcimadamore@1125 341 // and check for the end of comment.
mcimadamore@1125 342 if (comment_reader.ch == '*') {
mcimadamore@1125 343 // skip all of the stars
mcimadamore@1125 344 do {
mcimadamore@1125 345 comment_reader.scanCommentChar();
mcimadamore@1125 346 } while (comment_reader.ch == '*');
mcimadamore@1125 347
mcimadamore@1125 348 // check for the closing slash.
mcimadamore@1125 349 if (comment_reader.ch == '/') {
mcimadamore@1125 350 // We're done with the doc comment
mcimadamore@1125 351 // scanChar() and breakout.
mcimadamore@1125 352 break outerLoop;
mcimadamore@1125 353 }
mcimadamore@1125 354 } else if (! firstLine) {
jjg@1281 355 // The current line does not begin with a '*' so we will
jjg@1281 356 // treat it as comment
jjg@1281 357 comment_reader.bp = begin_bp;
jjg@1281 358 comment_reader.ch = begin_ch;
mcimadamore@1125 359 }
mcimadamore@1125 360 // The textLoop processes the rest of the characters
mcimadamore@1125 361 // on the line, adding them to our buffer.
mcimadamore@1125 362 textLoop:
mcimadamore@1125 363 while (comment_reader.bp < comment_reader.buflen) {
mcimadamore@1125 364 switch (comment_reader.ch) {
mcimadamore@1125 365 case '*':
mcimadamore@1125 366 // Is this just a star? Or is this the
mcimadamore@1125 367 // end of a comment?
mcimadamore@1125 368 comment_reader.scanCommentChar();
mcimadamore@1125 369 if (comment_reader.ch == '/') {
mcimadamore@1125 370 // This is the end of the comment,
mcimadamore@1125 371 // set ch and return our buffer.
mcimadamore@1125 372 break outerLoop;
mcimadamore@1125 373 }
mcimadamore@1125 374 // This is just an ordinary star. Add it to
mcimadamore@1125 375 // the buffer.
mcimadamore@1125 376 comment_reader.putChar('*', false);
mcimadamore@1125 377 break;
mcimadamore@1125 378 case ' ':
mcimadamore@1125 379 case '\t':
mcimadamore@1125 380 comment_reader.putChar(comment_reader.ch, false);
mcimadamore@1125 381 comment_reader.scanCommentChar();
mcimadamore@1125 382 break;
mcimadamore@1125 383 case FF:
mcimadamore@1125 384 comment_reader.scanCommentChar();
mcimadamore@1125 385 break textLoop; // treat as end of line
mcimadamore@1125 386 case CR: // (Spec 3.4)
mcimadamore@1125 387 comment_reader.scanCommentChar();
mcimadamore@1125 388 if (comment_reader.ch != LF) {
mcimadamore@1125 389 // Canonicalize CR-only line terminator to LF
mcimadamore@1125 390 comment_reader.putChar((char)LF, false);
mcimadamore@1125 391 break textLoop;
mcimadamore@1125 392 }
mcimadamore@1125 393 /* fall through to LF case */
mcimadamore@1125 394 case LF: // (Spec 3.4)
mcimadamore@1125 395 // We've seen a newline. Add it to our
mcimadamore@1125 396 // buffer and break out of this loop,
mcimadamore@1125 397 // starting fresh on a new line.
mcimadamore@1125 398 comment_reader.putChar(comment_reader.ch, false);
mcimadamore@1125 399 comment_reader.scanCommentChar();
mcimadamore@1125 400 break textLoop;
mcimadamore@1125 401 default:
mcimadamore@1125 402 // Add the character to our buffer.
mcimadamore@1125 403 comment_reader.putChar(comment_reader.ch, false);
mcimadamore@1125 404 comment_reader.scanCommentChar();
mcimadamore@1125 405 }
mcimadamore@1125 406 } // end textLoop
mcimadamore@1125 407 firstLine = false;
mcimadamore@1125 408 } // end outerLoop
mcimadamore@1125 409
mcimadamore@1125 410 if (comment_reader.sp > 0) {
mcimadamore@1125 411 int i = comment_reader.sp - 1;
mcimadamore@1125 412 trailLoop:
mcimadamore@1125 413 while (i > -1) {
mcimadamore@1125 414 switch (comment_reader.sbuf[i]) {
mcimadamore@1125 415 case '*':
mcimadamore@1125 416 i--;
mcimadamore@1125 417 break;
mcimadamore@1125 418 default:
mcimadamore@1125 419 break trailLoop;
mcimadamore@1125 420 }
mcimadamore@1125 421 }
mcimadamore@1125 422 comment_reader.sp = i + 1;
mcimadamore@1125 423
mcimadamore@1125 424 // Store the text of the doc comment
mcimadamore@1125 425 docComment = comment_reader.chars();
jjg@1281 426 docPosns = new int[comment_reader.pp];
jjg@1281 427 System.arraycopy(comment_reader.pbuf, 0, docPosns, 0, docPosns.length);
mcimadamore@1125 428 } else {
mcimadamore@1125 429 docComment = "";
mcimadamore@1113 430 }
mcimadamore@1125 431 } finally {
mcimadamore@1125 432 scanned = true;
jjg@1282 433 comment_reader = null;
mcimadamore@1125 434 if (docComment != null &&
mcimadamore@1125 435 docComment.matches("(?sm).*^\\s*@deprecated( |$).*")) {
mcimadamore@1125 436 deprecatedFlag = true;
mcimadamore@1125 437 }
mcimadamore@1113 438 }
mcimadamore@1113 439 }
mcimadamore@1113 440 }
mcimadamore@1113 441
mcimadamore@1113 442 @Override
mcimadamore@1113 443 public Position.LineMap getLineMap() {
mcimadamore@1113 444 char[] buf = reader.getRawCharacters();
mcimadamore@1113 445 return Position.makeLineMap(buf, buf.length, true);
mcimadamore@1113 446 }
mcimadamore@1113 447 }

mercurial