/* ____ ____ ____ ____ ______ *\ ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** ** /_____/\____/\___/\____/____/ ** \* */ // $Id$ package ch.epfl.lamp.util; /** * This class represents a position in a source file. Such a position * is defined by a source file (mandatory), a line number (optional) * and a column number (optional, may be specified only if the line * number is defined). * * Line (Column) numbers range from 0 to Integer.MAX_VALUE. A value of * 0 indicates that the line (column) is undefined, 1 represents the * first line (column). Negative values are prohibited. * * The class provides also functions to encode a line number and a * column number into one single integer. The encode line (column) * numbers range from 0 to LINE_MASK (COLUMN_MASK), where 0 indicates * that the line (column) is the undefined and 1 represents the first * line (column). Line (Column) numbers greater than LINE_MASK * (COLUMN_MASK) are replaced by LINE_MASK (COLUMN_MASK). Furthermore, * if the encoded line number is LINE_MASK, the column number is * always set to 0. * * The following properties hold: * - the undefined position is 0: encode(0,0) == 0 * - encodings are non-negative : encode(line,column) >= 0 * - position order is preserved: * (line1 < line2) || (line1 == line2 && column1 < column2) * implies * encode(line1,column1) <= encode(line2,column2) */ public class Position { //######################################################################## // Public Constants /** Number of bits used to encode the line number */ public static final int LINE_BITS = 20; /** Number of bits used to encode the column number */ public static final int COLUMN_BITS = 31 - LINE_BITS; // no negatives => 31 /** Mask to decode the line number */ public static final int LINE_MASK = (1 << LINE_BITS) - 1; /** Mask to decode the column number */ public static final int COLUMN_MASK = (1 << COLUMN_BITS) - 1; /** The undefined position */ public static final int NOPOS = 0; /** The first position in a source file */ public static final int FIRSTPOS = encode(1, 1); //######################################################################## // Public Functions /** Encodes a position into a single integer. */ public static int encode(int line, int column) { assert line >= 0 : line; assert line == 0 ? column == 0 : column >= 0 : line + "," + column; if (line >= LINE_MASK) { line = LINE_MASK; column = 0; } if (column > COLUMN_MASK) column = COLUMN_MASK; return (line << COLUMN_BITS) | column; } /** Returns the line number of the encoded position. */ public static int line(int position) { return (position >> COLUMN_BITS) & LINE_MASK; } /** Returns the column number of the encoded position. */ public static int column(int position) { return position & COLUMN_MASK; } //######################################################################## // Private Fields /** The position's file */ private final SourceFile file; /** The position's line number */ private final int line; /** The position's column number */ private final int column; //######################################################################## // Public Constructors /** Initializes a new instance. */ public Position(String source) { this(new SourceFile(source, new byte[0])); } /** Initializes a new instance. */ public Position(SourceFile file) { this(file, 0, 0); } /** Initializes a new instance. */ public Position(SourceFile file, int position) { this(file, line(position), column(position)); } /** Initializes a new instance. */ public Position(SourceFile file, int line, int column) { this.file = file; this.line = line; this.column = column; assert file != null; assert line >= 0 : line; assert line == 0 ? column == 0 : column >= 0 : line + "," + column; } //######################################################################## // Public Methods /** Returns the file of this position. */ public SourceFile file() { return file; } /** Returns the line number of this position. */ public int line() { return line; } /** Returns the column number of this position. */ public int column() { return column; } /** Returns an int encoding the line and column of this position. */ public int encodedLineColumn() { return encode(line, column); } /** Returns a string representation of this position. */ public String toString() { StringBuffer buffer = new StringBuffer(file.name()); if (line > 0) buffer.append(":").append(line); if (line > 0 && column > 0) buffer.append(":").append(column); return buffer.toString(); } /** Returns the hash code of this position. */ public int hashCode() { return file.hashCode() ^ encodedLineColumn(); } /** Returns true iff the given object represents the same position. */ public boolean equals(Object object) { if (!(object instanceof Position)) return false; Position that = (Position)object; return file == that.file && line == that.line && column == that.column; } //######################################################################## }