src/share/classes/com/sun/tools/javac/util/Position.java

changeset 1
9a66ca7c79fa
child 554
9d9f26857129
equal deleted inserted replaced
-1:000000000000 1:9a66ca7c79fa
1 /*
2 * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package com.sun.tools.javac.util;
27
28 import java.util.BitSet;
29 import static com.sun.tools.javac.util.LayoutCharacters.*;
30
31 /** A class that defines source code positions as simple character
32 * offsets from the beginning of the file. The first character
33 * is at position 0.
34 *
35 * Support is also provided for (line,column) coordinates, but tab
36 * expansion is optional and no Unicode excape translation is considered.
37 * The first character is at location (1,1).
38 *
39 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
40 * you write code that depends on this, you do so at your own risk.
41 * This code and its internal interfaces are subject to change or
42 * deletion without notice.</b>
43 */
44 public class Position {
45 public static final int NOPOS = -1;
46
47 public static final int FIRSTPOS = 0;
48 public static final int FIRSTLINE = 1;
49 public static final int FIRSTCOLUMN = 1;
50
51 public static final int LINESHIFT = 10;
52 public static final int MAXCOLUMN = (1<<LINESHIFT) - 1;
53 public static final int MAXLINE = (1<<(Integer.SIZE-LINESHIFT)) - 1;
54
55 public static final int MAXPOS = Integer.MAX_VALUE;
56
57 /**
58 * This is class is not supposed to be instantiated.
59 */
60 private Position() {}
61
62 /** A two-way map between line/column numbers and positions,
63 * derived from a scan done at creation time. Tab expansion is
64 * optionally supported via a character map. Text content
65 * is not retained.
66 *<p>
67 * Notes: The first character position FIRSTPOS is at
68 * (FIRSTLINE,FIRSTCOLUMN). No account is taken of Unicode escapes.
69 *
70 * @param src Source characters
71 * @param max Number of characters to read
72 * @param expandTabs If true, expand tabs when calculating columns
73 */
74 public static LineMap makeLineMap(char[] src, int max, boolean expandTabs) {
75 LineMapImpl lineMap = expandTabs ?
76 new LineTabMapImpl(max) : new LineMapImpl();
77 lineMap.build(src, max);
78 return lineMap;
79 }
80
81 /** Encode line and column numbers in an integer as:
82 * line-number << LINESHIFT + column-number
83 * {@link Position.NOPOS represents an undefined position.
84 *
85 * @param line number of line (first is 1)
86 * @param col number of character on line (first is 1)
87 * @return an encoded position or {@link Position.NOPOS
88 * if the line or column number is too big to
89 * represent in the encoded format
90 * @throws IllegalArgumentException if line or col is less than 1
91 */
92 public static int encodePosition(int line, int col) {
93 if (line < 1)
94 throw new IllegalArgumentException("line must be greater than 0");
95 if (col < 1)
96 throw new IllegalArgumentException("column must be greater than 0");
97
98 if (line > MAXLINE || col > MAXCOLUMN) {
99 return NOPOS;
100 }
101 return (line << LINESHIFT) + col;
102 }
103
104 public static interface LineMap extends com.sun.source.tree.LineMap {
105 /** Find the start position of a line.
106 *
107 * @param line number of line (first is 1)
108 * @return position of first character in line
109 * @throws ArrayIndexOutOfBoundsException
110 * if <tt>lineNumber < 1</tt>
111 * if <tt>lineNumber > no. of lines</tt>
112 */
113 int getStartPosition(int line);
114
115 /** Find the position corresponding to a (line,column).
116 *
117 * @param line number of line (first is 1)
118 * @param column number of character on line (first is 1)
119 *
120 * @return position of character
121 * @throws ArrayIndexOutOfBoundsException
122 * if <tt>line < 1</tt>
123 * if <tt>line > no. of lines</tt>
124 */
125 int getPosition(int line, int column);
126
127 /** Find the line containing a position; a line termination
128 * character is on the line it terminates.
129 *
130 * @param pos character offset of the position
131 * @return the line number on which pos occurs (first line is 1)
132 */
133 int getLineNumber(int pos);
134
135 /** Find the column for a character position.
136 * Note: this method does not handle tab expansion.
137 * If tab expansion is needed, use a LineTabMap instead.
138 *
139 * @param pos character offset of the position
140 * @return the column number at which pos occurs
141 */
142 int getColumnNumber(int pos);
143 }
144
145 static class LineMapImpl implements LineMap {
146 protected int[] startPosition; // start position of each line
147
148 protected LineMapImpl() {}
149
150 protected void build(char[] src, int max) {
151 int c = 0;
152 int i = 0;
153 int[] linebuf = new int[max];
154 while (i < max) {
155 linebuf[c++] = i;
156 do {
157 char ch = src[i];
158 if (ch == '\r' || ch == '\n') {
159 if (ch == '\r' && (i+1) < max && src[i+1] == '\n')
160 i += 2;
161 else
162 ++i;
163 break;
164 }
165 else if (ch == '\t')
166 setTabPosition(i);
167 } while (++i < max);
168 }
169 this.startPosition = new int[c];
170 System.arraycopy(linebuf, 0, startPosition, 0, c);
171 }
172
173 public int getStartPosition(int line) {
174 return startPosition[line - FIRSTLINE];
175 }
176
177 public long getStartPosition(long line) {
178 return getStartPosition(longToInt(line));
179 }
180
181 public int getPosition(int line, int column) {
182 return startPosition[line - FIRSTLINE] + column - FIRSTCOLUMN;
183 }
184
185 public long getPosition(long line, long column) {
186 return getPosition(longToInt(line), longToInt(column));
187 }
188
189 // Cache of last line number lookup
190 private int lastPosition = Position.FIRSTPOS;
191 private int lastLine = Position.FIRSTLINE;
192
193 public int getLineNumber(int pos) {
194 if (pos == lastPosition) {
195 return lastLine;
196 }
197 lastPosition = pos;
198
199 int low = 0;
200 int high = startPosition.length-1;
201 while (low <= high) {
202 int mid = (low + high) >> 1;
203 int midVal = startPosition[mid];
204
205 if (midVal < pos)
206 low = mid + 1;
207 else if (midVal > pos)
208 high = mid - 1;
209 else {
210 lastLine = mid + 1; // pos is at beginning of this line
211 return lastLine;
212 }
213 }
214 lastLine = low;
215 return lastLine; // pos is on this line
216 }
217
218 public long getLineNumber(long pos) {
219 return getLineNumber(longToInt(pos));
220 }
221
222 public int getColumnNumber(int pos) {
223 return pos - startPosition[getLineNumber(pos) - FIRSTLINE] + FIRSTCOLUMN;
224 }
225
226 public long getColumnNumber(long pos) {
227 return getColumnNumber(longToInt(pos));
228 }
229
230 private static int longToInt(long longValue) {
231 int intValue = (int)longValue;
232 if (intValue != longValue)
233 throw new IndexOutOfBoundsException();
234 return intValue;
235 }
236
237 protected void setTabPosition(int offset) {}
238 }
239
240 /**
241 * A LineMap that handles tab expansion correctly. The cost is
242 * an additional bit per character in the source array.
243 */
244 public static class LineTabMapImpl extends LineMapImpl {
245 private BitSet tabMap; // bits set for tab positions.
246
247 public LineTabMapImpl(int max) {
248 super();
249 tabMap = new BitSet(max);
250 }
251
252 protected void setTabPosition(int offset) {
253 tabMap.set(offset);
254 }
255
256 public int getColumnNumber(int pos) {
257 int lineStart = startPosition[getLineNumber(pos) - FIRSTLINE];
258 int column = 0;
259 for (int bp = lineStart; bp < pos; bp++) {
260 if (tabMap.get(bp))
261 column = (column / TabInc * TabInc) + TabInc;
262 else
263 column++;
264 }
265 return column + FIRSTCOLUMN;
266 }
267
268 public int getPosition(int line, int column) {
269 int pos = startPosition[line - FIRSTLINE];
270 column -= FIRSTCOLUMN;
271 int col = 0;
272 while (col < column) {
273 pos++;
274 if (tabMap.get(pos))
275 col = (col / TabInc * TabInc) + TabInc;
276 else
277 col++;
278 }
279 return pos;
280 }
281 }
282 }

mercurial