From d84ed1d80f6bde3af96ca135ca268efa60a09e5e Mon Sep 17 00:00:00 2001 From: paltherr Date: Sun, 21 Mar 2004 01:01:59 +0000 Subject: - Added Positon and SourceFile in scala/tools/util --- sources/scala/tools/util/Position.java | 170 +++++++++++++++++++++++++++++ sources/scala/tools/util/SourceFile.java | 177 +++++++++++++++++++++++++++++++ 2 files changed, 347 insertions(+) create mode 100644 sources/scala/tools/util/Position.java create mode 100644 sources/scala/tools/util/SourceFile.java (limited to 'sources') diff --git a/sources/scala/tools/util/Position.java b/sources/scala/tools/util/Position.java new file mode 100644 index 0000000000..9afdc78e7c --- /dev/null +++ b/sources/scala/tools/util/Position.java @@ -0,0 +1,170 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scala.tools.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; + } + + /** Returns a string representation of the encoded position. */ + public static String toString(int position) { + return line(position) + ":" + column(position); + } + + //######################################################################## + // 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; + } + + //######################################################################## +} diff --git a/sources/scala/tools/util/SourceFile.java b/sources/scala/tools/util/SourceFile.java new file mode 100644 index 0000000000..1014f7a0f7 --- /dev/null +++ b/sources/scala/tools/util/SourceFile.java @@ -0,0 +1,177 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scala.tools.util; + +import java.io.File; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; + + +/** This class represents a single source file. + */ +public class SourceFile { + + //######################################################################## + // Public Constants + + /** Constants used for source parsing */ + public static final byte LF = 0x0A; + public static final byte FF = 0x0C; + public static final byte CR = 0x0D; + public static final byte SU = 0x1A; + + //######################################################################## + // Private Fields + + /** The name of this source file */ + private final String name; + + /** The content of source this file */ + private final byte[] bytes; + + /** The encoding of this source file or null if unspecified */ + private String encoding; + + /** The position of the last line returned by getLine */ + private int lineNumber = 0; + private int lineStart = 0; + private int lineLength = 0; + private int nextIndex = 0; + + //######################################################################## + // Public Constructors + + /** Initializes a new instance. */ + public SourceFile(String name) throws IOException { + this(new File(name)); + } + + /** Initializes a new instance. */ + public SourceFile(File name) throws IOException { + this(name.toString(), read(name)); + } + + /** Initializes a new instance. */ + public SourceFile(String name, InputStream input) throws IOException { + this(name, read(name, input)); + } + + /** Initializes a new instance. */ + public SourceFile(String name, byte[] bytes) { + this.name = name; + this.bytes = normalize(bytes); + } + + //######################################################################## + // Public Methods + + /** Returns the name of this source file. */ + public String name() { + return name; + } + + /** Returns the content of this source file. */ + public byte[] bytes() { + return bytes; + } + + /** Sets the encoding of the file. */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** Returns the short name (name without path) of this source file. */ + public String getShortName() { + int start = name.lastIndexOf(File.separatorChar); + return start < 0 ? name : name.substring(start + 1); + } + + /** + * Returns an instance of Position representing the given line and + * column of this source file. + */ + public Position getPosition(int line, int column) { + return new Position(this, line, column); + } + + /** Returns the content of the given line. */ + public String getLine(int line) { + int index = lineNumber <= line ? nextIndex : (lineNumber = 0); + for (; index < bytes.length && lineNumber < line; lineNumber++) { + lineStart = index; + for (; index < bytes.length; index++) { + if (bytes[index] == CR) break; + if (bytes[index] == LF) break; + if (bytes[index] == FF) break; + } + lineLength = index - lineStart; + if (index < bytes.length) + index++; + if (index < bytes.length) + if (bytes[index - 1] == CR && bytes[index] == LF) index++; + } + nextIndex = index; + try { + return encoding != null ? + new String(bytes, lineStart, lineLength, encoding) : + new String(bytes, lineStart, lineLength); + } catch (UnsupportedEncodingException exception) { + throw new Error(exception); // !!! use ApplicationError + } + } + + /** Returns the name of this source file. */ + public String toString() { + return name; + } + + //######################################################################## + // Private Methods + + /** Reads the file and returns its content as a byte array. + */ + private static byte[] read(File file) throws IOException { + InputStream input = new FileInputStream(file); + try { + return read(file.toString(), input); + } finally { + input.close(); + } + } + + /** Reads the InputStream and returns its content as a byte array. + */ + private static byte[] read(String name, InputStream input) throws IOException { + try { + byte[] bytes = new byte[input.available() + 1]; + int numread = input.read(bytes); + if ((numread >= 0) && (numread != bytes.length - 1)) + throw new IOException(); + bytes[bytes.length - 1] = SU; + return bytes; + } catch (IOException exception) { + throw new IOException("cannot read '" + name + "'"); + } + } + + /** Ensures that the last byte of the array is SU. */ + private static byte[] normalize(byte[] input) { + if (input.length > 0 && input[input.length - 1] == SU) + return input; + byte[] bytes = new byte[input.length + 1]; + System.arraycopy(input, 0, bytes, 0, input.length); + bytes[input.length] = SU; + return bytes; + } + + //######################################################################## +} -- cgit v1.2.3