001: /*
002: * Position.java
003: *
004: * Copyright (C) 1998-2002 Peter Graves
005: * $Id: Position.java,v 1.2 2002/12/26 15:40:55 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: public final class Position implements Constants {
025: private Line line;
026: private int offset;
027:
028: public Position(Position pos) {
029: line = pos.line;
030: offset = pos.offset;
031: Debug.assertTrue(line != null);
032: }
033:
034: public Position(Line line, int offset) {
035: this .line = line;
036: this .offset = offset;
037: Debug.assertTrue(line != null);
038: }
039:
040: public final Position copy() {
041: return new Position(this );
042: }
043:
044: public final Line getLine() {
045: return line;
046: }
047:
048: public final void setLine(Line line) {
049: this .line = line;
050: }
051:
052: public final int getOffset() {
053: return offset;
054: }
055:
056: public final void setOffset(int offset) {
057: this .offset = offset;
058: }
059:
060: public final int getLineLength() {
061: return line.length();
062: }
063:
064: public final int lineNumber() {
065: return line.lineNumber();
066: }
067:
068: public final Line getNextLine() {
069: return line.next();
070: }
071:
072: public final Line getPreviousLine() {
073: return line.previous();
074: }
075:
076: public final boolean equals(Object obj) {
077: if (!(obj instanceof Position))
078: return false;
079: Position pos = (Position) obj;
080: return (line == pos.line && offset == pos.offset);
081: }
082:
083: public final boolean isBefore(Position pos) {
084: if (line.lineNumber() < pos.line.lineNumber())
085: return true;
086:
087: if (line == pos.line)
088: if (offset < pos.offset)
089: return true;
090:
091: return false;
092: }
093:
094: public final boolean isAfter(Position pos) {
095: if (line.lineNumber() > pos.line.lineNumber())
096: return true;
097:
098: if (line == pos.line)
099: if (offset > pos.offset)
100: return true;
101:
102: return false;
103: }
104:
105: public final void moveLeft() {
106: if (offset > 0)
107: --offset;
108: }
109:
110: public final void moveRight() {
111: if (offset < line.length())
112: ++offset;
113: }
114:
115: public final void moveTo(Position pos) {
116: line = pos.line;
117: offset = pos.offset;
118: Debug.assertTrue(line != null);
119: }
120:
121: public final void moveTo(Line line, int offset) {
122: this .line = line;
123: this .offset = offset;
124: Debug.assertTrue(line != null);
125: }
126:
127: // Moves position to the requested absolute column, based on the specified
128: // tab size. If the requested column is past the end of the line, position
129: // is moved to the end of the line.
130: public void moveToCol(int goal, int tabWidth) {
131: final int limit = line.length();
132: int i, col;
133: for (i = 0, col = 0; i < limit && col < goal; i++) {
134: if (line.charAt(i) == '\t')
135: col += tabWidth - col % tabWidth;
136: else
137: ++col;
138: }
139: offset = i;
140: }
141:
142: public final boolean lookingAt(String s) {
143: return s.regionMatches(0, line.getText(), offset, s.length());
144: }
145:
146: public final boolean lookingAtIgnoreCase(String s) {
147: return s.regionMatches(true, 0, line.getText(), offset, s
148: .length());
149: }
150:
151: public boolean atStart() {
152: if (line.previous() != null)
153: return false;
154: if (offset > 0)
155: return false;
156: return true;
157: }
158:
159: public boolean atEnd() {
160: if (line != null) {
161: if (offset < line.length())
162: return false;
163: if (line.next() != null)
164: return false;
165: }
166: return true;
167: }
168:
169: public boolean next() {
170: if (offset < line.length()) {
171: ++offset;
172: return true;
173: }
174: if (line.next() != null) {
175: line = line.next();
176: offset = 0;
177: return true;
178: }
179: return false;
180: }
181:
182: public boolean prev() {
183: if (offset > 0) {
184: --offset;
185: return true;
186: }
187: if (line.previous() != null) {
188: line = line.previous();
189: offset = line.length();
190: return true;
191: }
192: return false;
193: }
194:
195: public boolean nextLine() {
196: if (line.next() != null) {
197: line = line.next();
198: offset = 0;
199: return true;
200: }
201: return false;
202: }
203:
204: // No range checking!
205: public final void skip() {
206: ++offset;
207: }
208:
209: // No range checking!
210: public final void skip(int count) {
211: offset += count;
212: }
213:
214: public void skipWhitespace() {
215: while (Character.isWhitespace(getChar()) && next())
216: ;
217: }
218:
219: public void skipWhitespaceOnCurrentLine() {
220: int limit = line.length();
221: while (offset < limit
222: && Character.isWhitespace(line.charAt(offset)))
223: ++offset;
224: }
225:
226: // If we're looking at a single or double quote char, skip over quoted string.
227: public void skipQuote() {
228: char quoteChar = getChar();
229: if (quoteChar == '\'' || quoteChar == '"') {
230: while (next()) {
231: char c = getChar();
232: if (c == '\\') {
233: // Skip next char.
234: next();
235: continue;
236: }
237: if (c == quoteChar) {
238: // Point to char after quote.
239: next();
240: return;
241: }
242: }
243: }
244: }
245:
246: public char getChar() {
247: if (offset < 0 || offset > line.length()) {
248: Log.error("Position.getChar() offset = " + offset
249: + " line.length() = " + line.length());
250: Debug.assertTrue(false);
251: }
252: if (offset == line.length())
253: return EOL;
254: return line.charAt(offset);
255: }
256:
257: // Returns substring from position to end of line.
258: public final String getString() {
259: return line.substring(offset);
260: }
261:
262: // Returns identifier starting at this position.
263: public String getIdentifier(Mode mode) {
264: int begin = offset;
265: int end = offset;
266: final int limit = line.length();
267: while (mode.isIdentifierPart(line.charAt(end))) {
268: ++end;
269: if (end == limit)
270: break;
271: }
272: return line.substring(begin, end);
273: }
274:
275: public String toString() {
276: FastStringBuffer sb = new FastStringBuffer("line ");
277: if (line != null)
278: sb.append(line.lineNumber() + 1);
279: else
280: sb.append("is null");
281: sb.append(" col ");
282: sb.append(offset + 1);
283: return sb.toString();
284: }
285:
286: public final boolean isHidden() {
287: return line.isHidden();
288: }
289:
290: // Returns -1 if there's an error.
291: public static int getDistance(Position a, Position b) {
292: if (a == null || b == null)
293: return -1;
294: Debug.assertTrue(a.getLine() != null);
295: Debug.assertTrue(b.getLine() != null);
296: if (a.equals(b))
297: return 0;
298: Position pos, end;
299: if (a.isBefore(b)) {
300: pos = a.copy();
301: end = b.copy();
302: } else {
303: pos = b.copy();
304: end = a.copy();
305: }
306: final Line endLine = end.getLine();
307: int distance = 0;
308: while (pos.getLine() != endLine) {
309: distance += (pos.getLineLength() + 1 - pos.getOffset());
310: Line nextLine = pos.getNextLine();
311: if (nextLine == null)
312: return -1;
313: pos.moveTo(nextLine, 0);
314: }
315: Debug.assertTrue(pos.getLine() == endLine);
316: distance += end.getOffset() - pos.getOffset();
317: return distance;
318: }
319: }
|