summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpaltherr <paltherr@epfl.ch>2004-03-21 01:01:59 +0000
committerpaltherr <paltherr@epfl.ch>2004-03-21 01:01:59 +0000
commitd84ed1d80f6bde3af96ca135ca268efa60a09e5e (patch)
treec97d7f193d0ca589a4dc63625aa0518c6830d603
parent05f04931562a4a25476816fa13a71b26656bf3e5 (diff)
downloadscala-d84ed1d80f6bde3af96ca135ca268efa60a09e5e.tar.gz
scala-d84ed1d80f6bde3af96ca135ca268efa60a09e5e.tar.bz2
scala-d84ed1d80f6bde3af96ca135ca268efa60a09e5e.zip
- Added Positon and SourceFile in scala/tools/util
-rw-r--r--sources/scala/tools/util/Position.java170
-rw-r--r--sources/scala/tools/util/SourceFile.java177
2 files changed, 347 insertions, 0 deletions
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;
+ }
+
+ //########################################################################
+}