diff options
author | Martin Odersky <odersky@gmail.com> | 2003-02-13 14:41:36 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2003-02-13 14:41:36 +0000 |
commit | 4177daab2f54bdb20c71f623296a8bb32616fd12 (patch) | |
tree | 23f08b43f3758e825d5965b336030603a65bbcf7 /sources/scalac/util | |
parent | 33d6e170c97ca7b2f991896a0729941a7240b6d6 (diff) | |
download | scala-4177daab2f54bdb20c71f623296a8bb32616fd12.tar.gz scala-4177daab2f54bdb20c71f623296a8bb32616fd12.tar.bz2 scala-4177daab2f54bdb20c71f623296a8bb32616fd12.zip |
Initial version.
Diffstat (limited to 'sources/scalac/util')
-rw-r--r-- | sources/scalac/util/AbstractFile.java | 557 | ||||
-rw-r--r-- | sources/scalac/util/AbstractFileReader.java | 107 | ||||
-rw-r--r-- | sources/scalac/util/ArrayApply.java | 54 | ||||
-rw-r--r-- | sources/scalac/util/ClassPath.java | 161 | ||||
-rw-r--r-- | sources/scalac/util/Debug.java | 465 | ||||
-rw-r--r-- | sources/scalac/util/FreshNameCreator.java | 59 | ||||
-rw-r--r-- | sources/scalac/util/Name.java | 391 | ||||
-rw-r--r-- | sources/scalac/util/NameTransformer.java | 111 | ||||
-rw-r--r-- | sources/scalac/util/Names.java | 98 | ||||
-rw-r--r-- | sources/scalac/util/OptionParser.java | 546 | ||||
-rw-r--r-- | sources/scalac/util/Position.java | 54 | ||||
-rw-r--r-- | sources/scalac/util/PrefixMatcher.java | 114 | ||||
-rw-r--r-- | sources/scalac/util/Reporter.java | 192 | ||||
-rw-r--r-- | sources/scalac/util/SourceRepresentation.java | 205 | ||||
-rw-r--r-- | sources/scalac/util/Strings.java | 102 | ||||
-rw-r--r-- | sources/scalac/util/UniqueID.java | 30 |
16 files changed, 3246 insertions, 0 deletions
diff --git a/sources/scalac/util/AbstractFile.java b/sources/scalac/util/AbstractFile.java new file mode 100644 index 0000000000..2487e07ca3 --- /dev/null +++ b/sources/scalac/util/AbstractFile.java @@ -0,0 +1,557 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.util; + +import java.io.*; +import java.util.*; +import java.util.zip.*; +import java.util.jar.*; + +public abstract class AbstractFile { + + /** separator + */ + protected char separator = File.separatorChar; + + /** table of all opened jar-files + */ + protected static Hashtable opened = new Hashtable(); + + /** get name of the file + */ + public abstract String getName(); + + /** get path of the file + */ + public abstract String getPath(); + + /** does the file exist? + */ + public abstract boolean exists(); + + /** is the file a directory? + */ + public abstract boolean isDirectory(); + + /** read content of the file into a byte[] buffer + */ + public abstract byte[] read() throws IOException; + + /** list contents of a directory + */ + public abstract String[] list() throws IOException; + + /** open a new file + */ + public abstract AbstractFile open(String name); + + /** return an input stream for the file + */ + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(read()); + } + + /** open file 'name' in directory 'dirname' + */ + public static AbstractFile open(String dirname, String name) { + AbstractFile res; + if (dirname == null) + res = new PlainFile(new File(name)); + else if (dirname.endsWith(".zip")) { + AbstractFile dir = (AbstractFile)opened.get(dirname); + if (dir == null) { + dir = new ZipDir(new File(dirname)); + if (dir.isDirectory()) + opened.put(dirname, dir); + } + res = (name == null) ? dir : dir.open(name); + } else if (dirname.endsWith(".jar")) { + AbstractFile dir = (AbstractFile)opened.get(dirname); + if (dir == null) { + dir = new JarArchive(new File(dirname)); + if (dir.isDirectory()) + opened.put(dirname, dir); + } + res = (name == null) ? dir : dir.open(name); + } else if (name == null) + res = new PlainFile(new File(dirname)); + else + res = new PlainFile(new File(dirname, name)); + if (!res.exists()) + res = null; + return res; + } + + /** create file given by a fully qualified name from root directory `outdir'; + * create intermediate directories if they do not exist already + */ + public static File create(File outdir, String name, + String suffix) throws IOException { + int start = 0; + int end = name.indexOf('.'); + while (end >= start) { + outdir = new File(outdir, name.substring(start, end)); + if (!outdir.exists()) + outdir.mkdir(); + start = end + 1; + end = name.indexOf('.', start); + } + return new File(outdir, name.substring(start) + suffix); + } +} + +class PlainFile extends AbstractFile { + File f; + + PlainFile(File f) { + this.f = f; + } + + public String getName() { + return f.getName(); + } + + public String getPath() { + return f.getPath(); + } + + public boolean exists() { + return f.exists(); + } + + public boolean isDirectory() { + return f.isDirectory(); + } + + public byte[] read() throws IOException { + FileInputStream in = new FileInputStream(f); + int rest = (int)f.length(); + byte[] buf = new byte[rest]; + do { + int res = in.read(buf, buf.length - rest, rest); + if (res == -1) + throw new IOException("read error"); + rest -= res; + } while (rest > 0); + in.close(); + return buf; + } + + public String[] list() throws IOException { + File[] fs = f.listFiles(); + if (fs == null) + return new String[0]; + String[] res = new String[fs.length]; + for (int i = 0; i < fs.length; i++) { + res[i] = fs[i].getName(); + if (fs[i].isDirectory() && + !res[i].endsWith("/")) + res[i] = res[i] + "/"; + } + return res; + } + + public AbstractFile open(String name) { + return new PlainFile(new File(f, name)); + } +} + +class ZippedFile extends AbstractFile { + ZipDir dir; + ZipEntry zipEntry; + + { + separator = '/'; + } + + ZippedFile(ZipDir dir, String name) { + this.dir = dir; + if (dir.zipFile != null) { + name = name.replace(File.separatorChar, separator); + zipEntry = this.dir.zipFile.getEntry(name); + if (zipEntry == null) + zipEntry = this.dir.zipFile.getEntry(name + separator); + } + } + + public String getName() { + return zipEntry.getName(); + } + + public String getPath() { + return dir.getPath() + "(" + zipEntry.getName() + ")"; + } + + public boolean exists() { + return (zipEntry != null); + } + + public boolean isDirectory() { + return zipEntry.isDirectory(); + } + + public byte[] read() throws IOException { + InputStream in = dir.zipFile.getInputStream(zipEntry); + int rest = (int)zipEntry.getSize(); + byte[] buf = new byte[rest]; + do { + int res = in.read(buf, buf.length - rest, rest); + if (res == -1) + throw new IOException("read error"); + rest -= res; + } while (rest > 0); + in.close(); + return buf; + } + + public String[] list() throws IOException { + if (!isDirectory()) + throw new IOException("not a directory"); + return dir.list(zipEntry.getName()); + } + + public AbstractFile open(String name) { + String pathname = zipEntry.getName(); + return new ZippedFile(dir, pathname + name); + } +} + +class ZipDir extends AbstractFile { + File f; + ZipFile zipFile; + + { + separator = '/'; + } + + ZipDir(File f) { + this.f = f; + try { + zipFile = new ZipFile(f); + } catch (ZipException e) { + } catch (IOException e) {} + } + + public String getName() { + return f.getName(); + } + + public String getPath() { + return f.getPath(); + } + + public boolean exists() { + return (zipFile != null); + } + + public boolean isDirectory() { + return (zipFile != null); + } + + public byte[] read() throws IOException { + throw new IOException("cannot read directory"); + } + + public String[] list(String prefix) { + int n = 0; + for (Enumeration enum = zipFile.entries(); enum.hasMoreElements();) { + ZipEntry e = (ZipEntry)enum.nextElement(); + if (e.getName().startsWith(prefix)) { + String candidate = e.getName().substring(prefix.length()); + if (candidate.indexOf(separator) < 0) + n++; + } + } + String[] filenames = new String[n]; + n = 0; + for (Enumeration enum = zipFile.entries(); enum.hasMoreElements();) { + ZipEntry e = (ZipEntry)enum.nextElement(); + if (e.getName().startsWith(prefix)) { + String candidate = e.getName().substring(prefix.length()); + if (candidate.indexOf(separator) < 0) + filenames[n++] = candidate; + } + } + return filenames; + } + + public String[] list() throws IOException { + return list(""); + } + + public AbstractFile open(String name) { + return new ZippedFile(this, name); + } +} + +final class JarArchive extends AbstractFile { + File f; + JarFile jarFile; + HashMap entries; + + public final static String[] EMPTY = new String[0]; + + + JarArchive(File f) { + try { + jarFile = new JarFile(this.f = f); + } + catch (ZipException e) {} + catch (IOException e) {} + } + + public String getName() { + return f.getName(); + } + + public String getPath() { + return f.getPath(); + } + + public boolean exists() { + return jarFile != null; + } + + public boolean isDirectory() { + return jarFile != null; + } + + public byte[] read() throws IOException { + throw new IOException("cannot read archive"); + } + + private void load() { + entries = new HashMap(); + if (jarFile == null) + return; + Enumeration enum = jarFile.entries(); + while (enum.hasMoreElements()) { + String candidate = ((JarEntry)enum.nextElement()).getName(); + int i = candidate.indexOf('/'); + int j = 0; + HashMap files = entries; + while (i >= 0) { + String dirname = candidate.substring(j, j = (i + 1)); + JarDirEntry dir = (JarDirEntry)files.get(dirname); + if (dir == null) + files.put(dirname, dir = new JarDirEntry( + candidate.substring(0, j))); + files = dir.entries; + i = candidate.indexOf('/', j); + } + if (j < (candidate.length() - 1)) { + String filename = candidate.substring(j); + JarFileEntry file = (JarFileEntry)files.get(filename); + if (file == null) + files.put(filename, new JarFileEntry(candidate)); + } + } + } + + public String[] list(String prefix) { + prefix = prefix.replace(File.separatorChar, '/'); + if (entries == null) + load(); + int i = prefix.indexOf('/'); + int j = 0; + HashMap files = entries; + while (i >= 0) { + String dirname = prefix.substring(j, j = (i + 1)); + JarDirEntry dir = (JarDirEntry)files.get(dirname); + if (dir == null) + return EMPTY; + files = dir.entries; + i = prefix.indexOf('/', j); + } + if (j < (prefix.length() - 1)) { + String filename = prefix.substring(j); + return (files.get(filename) != null) ? new String[]{prefix} + : EMPTY; + } else + return (String[])files.keySet().toArray(new String[files.size()]); + } + + public String[] list() throws IOException { + return list(""); + } + + public AbstractFile open(String name) { + if (entries == null) + load(); + name = name.replace(File.separatorChar, '/'); + int i = name.indexOf('/'); + int j = 0; + int namelen = name.length(); + HashMap files = entries; + while (i >= 0) { + String dirname = name.substring(j, j = (i + 1)); + if (files != null) { + JarDirEntry dir = (JarDirEntry)files.get(dirname); + if (dir == null) + files = null; + else if (j == namelen) + return dir; + else + files = dir.entries; + } + i = name.indexOf('/', j); + } + if (j < (namelen - 1)) { + String filename = name.substring(j); + if (files == null) + return new NoJarFileEntry(name); + JarFileEntry file = (JarFileEntry)files.get(filename); + if (file == null) + return new NoJarFileEntry(name); + else + return file; + } else + return new NoJarDirEntry(name); + } + + static class NoJarDirEntry extends AbstractFile { + String name; + + NoJarDirEntry(String name) { + this.name = name; + } + + public String getName() { + return name.substring( + name.lastIndexOf('/', name.length() - 2) + 1); + } + + public String getPath() { + return name; + } + + public String getFullName() { + return name; + } + + public boolean exists() { + return false; + } + + public boolean isDirectory() { + return true; + } + + public String[] list() throws IOException { + throw new IOException("not a directory"); + } + + public byte[] read() throws IOException { + throw new IOException("cannot read archive"); + } + + public AbstractFile open(String fname) { + throw new Error("cannot open archive entry"); + } + } + + final class JarDirEntry extends NoJarDirEntry { + HashMap entries; + + JarDirEntry(String name) { + super(name); + this.entries = new HashMap(); + } + + public String getPath() { + return JarArchive.this.getPath() + "(" + name + ")"; + } + + public boolean exists() { + return true; + } + + public String[] list() throws IOException { + return JarArchive.this.list(name); + } + + public AbstractFile open(String fname) { + fname = fname.replace(File.separatorChar, '/'); + return JarArchive.this.open(name + fname); + } + } + + static class NoJarFileEntry extends AbstractFile { + String name; + + NoJarFileEntry(String name) { + this.name = name; + } + + public String getName() { + return name.substring( + name.lastIndexOf('/', name.length() - 1) + 1); + } + + public String getFullName() { + return name; + } + + public String getPath() { + return name; + } + + public boolean exists() { + return false; + } + + public boolean isDirectory() { + return false; + } + + public String[] list() throws IOException { + throw new IOException("not a directory"); + } + + public byte[] read() throws IOException { + throw new IOException("cannot read archive"); + } + + public AbstractFile open(String fname) { + throw new Error("not a directory"); + } + } + + final class JarFileEntry extends NoJarFileEntry { + + JarFileEntry(String name) { + super(name); + } + + public String getPath() { + return JarArchive.this.getPath() + "(" + name + ")"; + } + + public boolean exists() { + return true; + } + + public byte[] read() throws IOException { + JarEntry jarEntry = jarFile.getJarEntry(name); + if (jarEntry == null) + throw new IOException("unable to read " + name); + InputStream in = jarFile.getInputStream(jarEntry); + int rest = (int)jarEntry.getSize(); + byte[] buf = new byte[rest]; + do { + int res = in.read(buf, buf.length - rest, rest); + if (res == -1) + throw new IOException("read error"); + rest -= res; + } while (rest > 0); + in.close(); + return buf; + } + } +} diff --git a/sources/scalac/util/AbstractFileReader.java b/sources/scalac/util/AbstractFileReader.java new file mode 100644 index 0000000000..0d18292838 --- /dev/null +++ b/sources/scalac/util/AbstractFileReader.java @@ -0,0 +1,107 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.util; + +import java.io.*; + + +public class AbstractFileReader { + + /** the buffer containing the file + */ + public byte[] buf; + + /** the current input pointer + */ + public int bp; + + /** constructor + */ + public AbstractFileReader(AbstractFile f) throws IOException { + buf = f.read(); + bp = 0; + } + + /** return byte at offset 'pos' + */ + public byte byteAt(int pos) { + return buf[pos]; + } + + /** read a byte + */ + public byte nextByte() { + return buf[bp++]; + } + + /** read some bytes + */ + public byte[] nextBytes(int len) { + byte[] res = new byte[len]; + System.arraycopy(buf, bp, res, 0, len); + bp += len; + return res; + } + + /** read a character + */ + public char nextChar() { + return + (char)(((buf[bp++] & 0xff) << 8) + + (buf[bp++] & 0xff)); + } + + /** read an integer + */ + public int nextInt() { + return ((buf[bp++] & 0xff) << 24) + + ((buf[bp++] & 0xff) << 16) + + ((buf[bp++] & 0xff) << 8) + + (buf[bp++] & 0xff); + } + + /** extract a character at position bp from buf + */ + public char getChar(int bp) { + return (char)(((buf[bp] & 0xff) << 8) + (buf[bp+1] & 0xff)); + } + + /** extract an integer at position bp from buf + */ + public int getInt(int bp) { + return ((buf[bp ] & 0xff) << 24) + + ((buf[bp+1] & 0xff) << 16) + + ((buf[bp+2] & 0xff) << 8) + + (buf[bp+3] & 0xff); + } + + /** extract a long integer at position bp from buf + */ + public long getLong(int bp) { + return ((long)(getInt(bp)) << 32) + (getInt(bp + 4) & 0xffffffffL); + } + + /** extract a float at position bp from buf + */ + public strictfp float getFloat(int bp) { + return Float.intBitsToFloat(getInt(bp)); + } + + /** extract a double at position bp from buf + */ + public strictfp double getDouble(int bp) { + return Double.longBitsToDouble(getLong(bp)); + } + + /** skip next 'n' bytes + */ + public void skip(int n) { + bp += n; + } +} diff --git a/sources/scalac/util/ArrayApply.java b/sources/scalac/util/ArrayApply.java new file mode 100644 index 0000000000..087278af5b --- /dev/null +++ b/sources/scalac/util/ArrayApply.java @@ -0,0 +1,54 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scalac.util; + +public abstract class ArrayApply { + + //######################################################################## + // Arrays interface - Object + + public static String toString(Object[] src) { + return append(new StringBuffer(), src).toString(); + } + + public static String toString(Object[] src, String infix) { + return append(new StringBuffer(), src, infix).toString(); + } + + public static String toString(Object[] src, String prefix, String infix, + String suffix) + { + return append(new StringBuffer(), src, prefix,infix,suffix).toString(); + } + + //######################################################################## + // Arrays interface - StringBuffer + + public static StringBuffer append(StringBuffer buffer, Object[] src) { + return append(buffer, src, "[", ",", "]"); + } + + public static StringBuffer append(StringBuffer buffer, Object[] src, + String infix) + { + return append(buffer, src, "", infix, ""); + } + + public static StringBuffer append(StringBuffer buffer, Object[] src, + String prefix, String infix, String suffix) + { + buffer.append(prefix); + for (int i = 0; i < src.length; i++) { + if (i > 0) buffer.append(infix); + buffer.append(src[i]); + } + buffer.append(suffix); + return buffer; + } +} diff --git a/sources/scalac/util/ClassPath.java b/sources/scalac/util/ClassPath.java new file mode 100644 index 0000000000..b083c5485b --- /dev/null +++ b/sources/scalac/util/ClassPath.java @@ -0,0 +1,161 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.util; + +import java.io.*; +import java.util.*; + + +public class ClassPath { + + /** the character separating files + */ + protected static String FILE_SEP = File.separator; + + /** the separator in class path specifications + */ + protected static String PATH_SEP = + System.getProperty("path.separator"); + + /** the default class path + */ + public static String CLASS_PATH = + System.getProperty("scala.class.path", + System.getProperty("java.class.path")); + + /** the default source path + */ + public static String SOURCE_PATH = null; + + /** the default boot class path + */ + public static String BOOT_PATH = + appendPath(appendPath("", System.getProperty("sun.boot.class.path")), + System.getProperty("scala.boot.class.path")).substring(1); + + /** the default extension path + */ + public static String EXTENSION_PATH = + System.getProperty("java.ext.dirs"); + + /** the various class path roots + */ + protected String[] root; + + /** print searches in the class path + */ + public boolean printSearch; + + + /** classpath constructor + */ + public ClassPath() { + this(CLASS_PATH); + } + + public ClassPath(String classpath) { + this(classpath, SOURCE_PATH, BOOT_PATH, EXTENSION_PATH); + } + + public ClassPath(String classpath, String sourcepath, + String bootclasspath, String extdirs) + { + String path = ""; + path = appendPath(path, bootclasspath); + path = appendExtDirs(path, extdirs); + path = appendPath(path, classpath); + path = appendPath(path, sourcepath); + root = parse(path.substring(1)); + } + + /** append an additional path + */ + protected static String appendPath(String path, String addpath) { + return addpath == null ? path : path + PATH_SEP + addpath; + } + + /** append files from the extension directories + */ + protected String appendExtDirs(String path, String extdirs) { + if (extdirs != null) { + extdirs += PATH_SEP; + int length = extdirs.length(); + int i = 0; + while (i < length) { + int k = extdirs.indexOf(PATH_SEP, i); + String dirname = extdirs.substring(i, k); + String[] ext; + if ((dirname != null) && + (dirname.length() > 0) && + ((ext = new File(dirname).list()) != null)) { + if (!dirname.endsWith(FILE_SEP)) + dirname += FILE_SEP; + for (int j = 0; j < ext.length; j++) + if (ext[j].endsWith(".jar") || + ext[j].endsWith(".zip")) + path = appendPath(path, dirname + ext[j]); + } + i = k + 1; + } + } + return path; + } + + /** parse a class path specification and return an array + * of existing class file locations + */ + protected String[] parse(String path) { + path += PATH_SEP; + Vector components = new Vector(); + int i = 0; + while (i < path.length()) { + int j = path.indexOf(PATH_SEP, i); + String subpath = path.substring(i, j); + if (new File(subpath).exists()) + components.add(subpath); + i = j + 1; + } + return (String[])components.toArray( + new String[components.size()]); + } + + /** find file with given name in class path and return an abstract + * file representation + */ + public AbstractFile openFile(String name) throws FileNotFoundException { + if (printSearch) + System.out.println("looking for " + name); + for (int i = 0; i < root.length; i++) { + if (printSearch) + System.out.println(" in " + root[i]); + AbstractFile f = AbstractFile.open(root[i], name); + if (f != null) + return f; + } + throw new FileNotFoundException("file '" + name + + "' not found in classpath"); + } + + public String[] components() { + return root; + } + + /** return a textual representation of this class path + */ + public String toString() { + if (root.length == 0) + return ""; + else if (root.length == 1) + return root[0]; + String path = root[0]; + for (int i = 1; i < root.length; i++) + path += PATH_SEP + root[i]; + return path; + } +} diff --git a/sources/scalac/util/Debug.java b/sources/scalac/util/Debug.java new file mode 100644 index 0000000000..4597463aab --- /dev/null +++ b/sources/scalac/util/Debug.java @@ -0,0 +1,465 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $Id$ + +package scalac.util; + +import java.util.HashMap; + +import java.lang.reflect.Modifier; +import java.lang.reflect.Method; +import java.lang.reflect.Field; + +import scalac.Global; +import scalac.ApplicationError; +import scalac.symtab.Type; +import scalac.symtab.Symbol; +import scalac.symtab.Scope; + +/** + * Debugging class, used e.g. to obtain string representations of + * compiler data structures that are not "pretty-printed" and thus + * easier to relate to the source code. + * + * All methods are static to be easily useable in any context. + * + * @author Michel Schinz + * @version 1.0 + */ + +public abstract class Debug { + + //######################################################################## + // Debug interface - abort + + public static Error abort() { + return new ApplicationError(); + } + + public static Error abort(String message) { + return new ApplicationError(message); + } + + public static Error abort(Object object) { + return new ApplicationError(object); + } + + public static Error abort(Throwable cause) { + return new ApplicationError(cause); + } + + public static Error abort(String message, Object object) { + return new ApplicationError(message, object); + } + + public static Error abort(String message, Throwable cause) { + return new ApplicationError(message, cause); + } + + public static Error abort(Object object, Throwable cause) { + return new ApplicationError(object, cause); + } + + public static Error abort(String message, Object object, Throwable cause) { + return new ApplicationError(message, object, cause); + } + + //######################################################################## + // Debug interface - log + + public static boolean log(String message) { + return Global.instance.log(message); + } + + public static boolean log(String message, Object object) { + return log(message + ": " + show(object)); + } + + //######################################################################## + // Debug interface - handlers + + public static final HashMap/*<Class,DebugHandler>*/ handlers; + + static { + handlers = new HashMap(); + handlers.put(String.class, DebugToStringHandler.instance); + handlers.put(Type.class, DebugType.instance); + handlers.put(Symbol.class, DebugSymbol.instance); + handlers.put(Scope.class, DebugScope.instance); + } + + public static DebugHandler getHandler(Object that) { + if (that == null) return DebugDefaultHandler.instance; + return getHandler(that.getClass()); + } + + public static DebugHandler getHandler(Class clasz) { + if (clasz == null) return DebugDefaultHandler.instance; + Object handler = handlers.get(clasz); + if (handler != null) return (DebugHandler)handler; + return getHandler(clasz.getSuperclass()); + } + + //######################################################################## + // Debug interface - toString + + public static String toString(Object that) { + return show(that); + } + + //######################################################################## + // Debug interface - show + + public static String show(Object that) { + return show(that, getHandler(that)); + } + + public static String show(Object that, DebugHandler handler) { + StringBuffer buffer = new StringBuffer(); + handler.append0(buffer, that); + return buffer.toString(); + } + + //######################################################################## + // Debug interface - append + + public static void append(StringBuffer buffer, Object that) { + getHandler(that).append0(buffer, that); + } + + public static void appendDefault(StringBuffer buffer, Object that) { + if (that == null) { buffer.append("null"); return; } + if (!that.getClass().isArray()) { + appendObject(buffer, that); + } else { + appendArray(buffer, (Object[])that); + } + } + + public static void appendObject(StringBuffer buffer, Object that) { + if (that == null) { buffer.append("null"); return; } + buffer.append(getClassName(that)); + Class owner = null; + if (hasToString(that.getClass())) { + buffer.append('('); + buffer.append(that); + buffer.append(')'); + } else { + int code = System.identityHashCode(that); + buffer.append('@'); + buffer.append(Integer.toHexString(code)); + } + } + + public static void appendArray(StringBuffer buffer, Object[] that) { + if (that == null) { buffer.append("null"); return; } + buffer.append('['); + for (int i = 0; i < that.length; i++) { + if (i > 0) buffer.append(','); + append(buffer, that[i]); + } + buffer.append(']'); + } + + //######################################################################## + // Debug interface - utils + + public static final Class OBJECT_CLASS = Object.class; + + public static boolean hasToString(Class clasz) { + try { + Method toString = clasz.getMethod("toString", new Class[0]); + return toString.getDeclaringClass() != OBJECT_CLASS; + } catch (NoSuchMethodException excpetion) { + return false; + } catch (SecurityException excpetion) { + return false; + } + } + + public static String getClassName(Object object) { + if (object == null) return "null"; + Class clasz = object.getClass(); + String name = clasz.getName(); + if (!name.endsWith("$$Var")) return name; + Class superclass = clasz.getSuperclass(); + Field[] fields = superclass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + try { + Field field = fields[i]; + if (field.getType() != clasz) continue; + if (!Modifier.isStatic(field.getModifiers())) continue; + Object value = field.get(null); + if (value != object) continue; + return name + "[" + field.getName() + "]"; + } catch (IllegalAccessException exception) { + // continue + } + } + return name; + } + + //######################################################################## +} + +public interface DebugHandler { + + //######################################################################## + // DebugHandler interface + + public void append0(StringBuffer buffer, Object that); + + //######################################################################## +} + +public abstract class DebugAbstractHandler implements DebugHandler { + + //######################################################################## + // DebugAbstractHandler interface + + public String show(Object that) { + return Debug.show(that, this); + } + + //######################################################################## +} + +public class DebugDefaultHandler extends DebugAbstractHandler { + + //######################################################################## + // DebugDefaultHandler interface + + public static DebugDefaultHandler instance = new DebugDefaultHandler(); + + //######################################################################## + // DebugHandler interface + + public void append0(StringBuffer buffer, Object that) { + Debug.appendDefault(buffer, that); + } + + //######################################################################## +} + +public class DebugToStringHandler extends DebugAbstractHandler { + + //######################################################################## + // DebugToStringHandler interface + + public static DebugToStringHandler instance = new DebugToStringHandler(); + + //######################################################################## + // DebugHandler interface + + public void append0(StringBuffer buffer, Object that) { + buffer.append(that); + } + + //######################################################################## +} + +public class DebugObject extends DebugAbstractHandler { + + //######################################################################## + // DebugObject interface + + public static DebugObject instance = new DebugObject(); + + public void append1(StringBuffer buffer, Object that) { + Debug.appendObject(buffer, that); + } + + //######################################################################## + // DebugHandler interface + + public void append0(StringBuffer buffer, Object that) { + append1(buffer, (Object)that); + } + + //######################################################################## +} + +public class DebugArray extends DebugAbstractHandler { + + //######################################################################## + // DebugArray interface + + public static DebugArray instance = new DebugArray(); + + public void append1(StringBuffer buffer, Object[] that) { + Debug.appendArray(buffer, that); + } + + //######################################################################## + // DebugHandler interface + + public void append0(StringBuffer buffer, Object that) { + append1(buffer, (Object[])that); + } + + //######################################################################## +} + +public class DebugType extends DebugAbstractHandler { + + //######################################################################## + // DebugType interface + + public static DebugType instance = new DebugType(); + + public void append1(StringBuffer buffer, Type that) { + switch (that) { + + case ErrorType: + buffer.append("ErrorType"); + return; + + case AnyType: + buffer.append("AnyType"); + return; + + case NoType: + buffer.append("NoType"); + return; + + case ThisType(Symbol symbol): + buffer.append("ThisType("); + Debug.append(buffer, symbol); + buffer.append(')'); + return; + + case TypeRef(Type prefix, Symbol symbol, Type[] args) : + buffer.append("TypeRef("); + Debug.append(buffer, prefix); + buffer.append(','); + Debug.append(buffer, symbol); + buffer.append(','); + Debug.append(buffer, args); + buffer.append(')'); + return; + + case SingleType(Type prefix, Symbol symbol): + buffer.append("SingleType("); + Debug.append(buffer, prefix); + buffer.append(','); + Debug.append(buffer, symbol); + buffer.append(')'); + return; + + case CompoundType(Type[] basetypes, Scope members): + buffer.append("CompoundType("); + Debug.append(buffer, basetypes); + buffer.append(','); + Debug.append(buffer, members); + buffer.append(')'); + return; + + case MethodType(Symbol[] vparams, Type result): + buffer.append("MethodType("); + Debug.append(buffer, vparams); + buffer.append(','); + Debug.append(buffer, result); + buffer.append(')'); + return; + + case PolyType(Symbol[] tparams, Type result): + buffer.append("PolyType("); + Debug.append(buffer, tparams); + buffer.append(','); + Debug.append(buffer, result); + buffer.append(')'); + return; + + case CovarType(Type tp): + buffer.append("CovarType("); + Debug.append(buffer, tp); + buffer.append(')'); + return; + + case OverloadedType(Symbol[] alts, Type[] alttypes): + buffer.append("OverloadedType("); + Debug.append(buffer, alts); + buffer.append(','); + Debug.append(buffer, alttypes); + buffer.append(')'); + return; + + default: + Debug.appendDefault(buffer, that); + return; + } + } + + //######################################################################## + // DebugHandler interface + + public void append0(StringBuffer buffer, Object that) { + append1(buffer, (Type)that); + } + + //######################################################################## +} + +public class DebugSymbol extends DebugAbstractHandler { + + //######################################################################## + // DebugSymbol interface + + public static DebugSymbol instance = new DebugSymbol(); + + public void append1(StringBuffer buffer, Symbol that) { + if (that != Symbol.NONE && that != Symbol.ERROR) { + buffer.append(that.kindString()).append(' '); + if (that.owner() != Global.instance.definitions.ROOT_CLASS) { + buffer.append(that.owner().fullName()); + buffer.append("::"); + } + } + buffer.append(that.name); + if (Global.instance.uniqid) { + buffer.append('#'); + buffer.append(Global.instance.uniqueID.id(that)); + } + } + + //######################################################################## + // DebugHandler interface + + public void append0(StringBuffer buffer, Object that) { + append1(buffer, (Symbol)that); + } + + //######################################################################## +} + +public class DebugScope extends DebugAbstractHandler { + + //######################################################################## + // DebugScope interface + + public static DebugScope instance = new DebugScope(); + + public void append1(StringBuffer buffer, Scope that) { + buffer.append('{'); + for (Scope.SymbolIterator i = that.iterator(); i.hasNext();) { + Debug.append(buffer, i.next()); + if (i.hasNext()) buffer.append(','); + } + buffer.append('}'); + } + + //######################################################################## + // DebugHandler interface + + public void append0(StringBuffer buffer, Object that) { + append1(buffer, (Scope)that); + } + + //######################################################################## +} + diff --git a/sources/scalac/util/FreshNameCreator.java b/sources/scalac/util/FreshNameCreator.java new file mode 100644 index 0000000000..fb69ad5c33 --- /dev/null +++ b/sources/scalac/util/FreshNameCreator.java @@ -0,0 +1,59 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scalac.util; + +import java.util.HashMap; + +public class FreshNameCreator { + + protected int counter = 0; + protected HashMap counters = new HashMap(); + + /** + * Create a fresh name with the given prefix. It is guaranteed + * that the returned name has never been returned by a previous + * call to this function with the same separator character (which + * has to be a non-digit). + */ + public Name newName(String prefix, char separator) { + prefix += separator; + Integer ival = (Integer)counters.get(prefix); + if (ival == null) + counters.put(prefix, ival = new Integer(0)); + else + counters.put(prefix, ival = new Integer(ival.intValue() + 1)); + return Name.fromString(prefix + ival); + } + + /** Same, with `$' as the separator character + */ + public Name newName(String prefix) { + return newName(prefix, '$'); + } + + /** Same, but with a name as prefix. The new name is a type + * (respectively, constructor) name if the prefix is one. + */ + public Name newName(Name prefixName, char separator) { + Name name = newName(prefixName.toString(), separator); + if (prefixName.isTypeName()) return name.toTypeName(); + else if (prefixName.isConstrName()) return name.toConstrName(); + else return name; + } + + /** Same, with `$' as the separator character + */ + public Name newName(Name prefix) { + return newName(prefix, '$'); + } + + public Name newName() { + return Name.fromString("$" + (counter++) + "$"); + } +} diff --git a/sources/scalac/util/Name.java b/sources/scalac/util/Name.java new file mode 100644 index 0000000000..0c04fe2dcb --- /dev/null +++ b/sources/scalac/util/Name.java @@ -0,0 +1,391 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.util; + +public final class Name { + +/** address in the name memory + */ + public int index; + +/** length of the name + */ + private int len; + +/** next name in the same hash bucket + */ + private Name next; + + private final static int HASH_SIZE = 0x8000; + private final static int HASH_MASK = 0x7FFF; + private final static int NAME_SIZE = 0x20000; + +/** memory to store all names sequentially + */ + public static byte[] names = new byte[NAME_SIZE]; + private static int nc = 0; + +/** hashtable for finding term names quickly + */ + private static Name[] termHashtable = new Name[HASH_SIZE]; + +/** hashtable for finding type names quickly + */ + private static Name[] typeHashtable = new Name[HASH_SIZE]; + +/** hashtable for finding constructor names quickly + */ + private static Name[] constrHashtable = new Name[HASH_SIZE]; + +/** Constructor + */ + Name(int index, int len, Name[] table, int hash) { + this.index = index; + this.len = len; + this.next = table[hash]; + table[hash] = this; + } + +/** the hashcode of a name + */ + private static int hashValue(byte cs[], int offset, int len) { + if (len > 0) + return + len * (41 * 41 * 41) + + cs[offset] * (41 * 41) + + cs[offset + len - 1] * 41 + + cs[offset + (len >> 1)]; + else + return 0; + } + +/** is (the ascii representation of) name equal to + * cs[offset..offset+len-1]? + */ + private static boolean equals(int index, byte cs[], int offset, int len) { + int i = 0; + while ((i < len) && (names[index + i] == cs[offset + i])) + i++; + return i == len; + } + +/** the empty name + */ + public static final Name EMPTY = fromString(""); + +/** create a term name from the bytes in cs[offset..offset+len-1]. + * assume that bytes are in ascii format. + */ + public static Name fromAscii(byte cs[], int offset, int len) { + int h = hashValue(cs, offset, len) & HASH_MASK; + Name n = termHashtable[h]; + while ((n != null) && (n.len != len || !equals(n.index, cs, offset, len))) + n = n.next; + if (n == null) { + n = new Name(nc, len, termHashtable, h); + for (int i = 0; i < len; i++) + { + if (nc == names.length) + { + byte[] newnames = new byte[names.length * 2]; + System.arraycopy(names, 0, newnames, 0, names.length); + names = newnames; + } + names[nc++] = cs[offset + i]; + } + if (len == 0) + nc++; + } + return n; + } + +/** create a name from the bytes in cs[offset..offset+len-1]; + * assume that characters are in source format + */ + public static Name fromSource(byte cs[], int offset, int len) { + byte[] ascii = new byte[len * 2]; + int alen = SourceRepresentation.source2ascii(cs, offset, len, ascii); + return fromAscii(ascii, 0, alen); + } + +/** create a name from the characters in string s + */ + public static Name fromString(String s) { + byte[] source = SourceRepresentation.string2source(s); + return fromSource(source, 0, source.length); + } + +/** copy bytes of this name to buffer cs, starting at offset + */ + public void copyAscii(byte cs[], int offset) { + System.arraycopy(names, index, cs, offset, len); + } + +/** return the ascii representation of this name + */ + public byte[] toAscii() { + byte[] ascii = new byte[len]; + System.arraycopy(names, index, ascii, 0, len); + return ascii; + } + +/** return the source representation of this name + */ + public byte[] toSource() { + return SourceRepresentation.string2source(toString()); + } + +/** return the string representation of this name + */ + public String toString() { + return SourceRepresentation.ascii2string(names, index, len); + } + +/** is this name a term name? + */ + public boolean isTermName() { + int h = hashValue(names, index, len) & HASH_MASK; + Name n = termHashtable[h]; + while (n != null && n != this) + n = n.next; + return n == this; + } + +/** is this name a type name? + */ + public boolean isTypeName() { + int h = hashValue(names, index, len) & HASH_MASK; + Name n = typeHashtable[h]; + while (n != null && n != this) + n = n.next; + return n == this; + } + +/** is this name a type name? + */ + public boolean isConstrName() { + int h = hashValue(names, index, len) & HASH_MASK; + Name n = constrHashtable[h]; + while (n != null && n != this) + n = n.next; + return n == this; + } + +/** create a term name corresponding to this name + */ + public Name toTermName() { + int h = hashValue(names, index, len) & HASH_MASK; + Name n = termHashtable[h]; + while (n != null && n.index != index) + n = n.next; + if (n == null) { + n = new Name(index, len, termHashtable, h); + } + return n; + } + +/** create a type name corresponding to this name + */ + public Name toTypeName() { + int h = hashValue(names, index, len) & HASH_MASK; + Name n = typeHashtable[h]; + while (n != null && n.index != index) + n = n.next; + if (n == null) { + n = new Name(index, len, typeHashtable, h); + } + return n; + } + +/** create a constructor name corresponding to this name + */ + public Name toConstrName() { + int h = hashValue(names, index, len) & HASH_MASK; + Name n = constrHashtable[h]; + while (n != null && n.index != index) + n = n.next; + if (n == null) { + n = new Name(index, len, constrHashtable, h); + } + return n; + } + +/** return the string hash value of this name + */ + public int hashCode() { + return index; + } + +/** returns the length of this name + */ + public int length() { + return len; + } + +/** returns i'th byte of this name + */ + public byte sub(int i) { + return names[index + i]; + } + +/** returns first occurrence of byte b in this name, len if not found + */ + public int pos(byte b) { + return pos(b, 0); + } + +/** returns first occurrence of byte b in this name from `start', len if not found + */ + public int pos(byte b, int start) { + int i = start; + while (i < len && names[index + i] != b) + i++; + return i; + } + +/** returns last occurrence of byte b in this name, -1 if not found. + */ + public int lastPos(byte b) { + int i = len - 1; + while (i >= 0 && names[index + i] != b) + i--; + return i; + } + +/** does this name start with prefix? + */ + public boolean startsWith(Name prefix) { + int i = 0; + while ((i < prefix.len) && + (i < len) && + (names[index + i] == names[prefix.index + i])) + i++; + return i == prefix.len; + } + +/** does this name end with suffix? + */ + public boolean endsWith(Name suffix) { + int i = len - 1; + int j = suffix.len - 1; + while ((j >= 0) && (i >= 0) && + (names[index + i] == names[suffix.index + j])) { + i--; + j--; + } + return j < 0; + } + +/** returns the subName starting at position start, excluding position end + */ + public Name subName(int start, int end) { + if (end < start) + end = start; + byte[] ascii = new byte[end - start]; + System.arraycopy(names, index + start, ascii, 0, end - start); + return fromAscii(ascii, 0, ascii.length); + } + +/** replace all `from' characters with `to' + */ + public Name replace(byte from, byte to) { + byte[] ascii = new byte[len]; + copyAscii(ascii, 0); + for (int i = 0; i < len; i++) + if (ascii[i] == from) ascii[i] = to; + return fromAscii(ascii, 0, len); + } + +/** returns the concatenation of this name and n + */ + public Name append(Name n) { + byte[] ascii = new byte[len + n.len]; + copyAscii(ascii, 0); + n.copyAscii(ascii, len); + return fromAscii(ascii, 0, ascii.length); + } + +/** returns the concatenation of all names in ns + */ + public static Name concat(Name ns[]) { + int len = 0; + for (int i = 0; i < ns.length; i++) + len = len + ns[i].len; + byte[] ascii = new byte[len]; + len = 0; + for (int i = 0; i < ns.length; i++) { + ns[i].copyAscii(ascii, len); + len = len + ns[i].len; + } + return fromAscii(ascii, 0, len); + } + +/** is this name an operator? + */ + public boolean isOperator() { + return !(((names[index] >= 'a') && (names[index] <= 'z')) || + ((names[index] >= 'A') && (names[index] <= 'Z')) || + (names[index] == '$') || + (names[index] == '_')); + } + +/** is this name a variable identifier? + */ + public boolean isVariable() { + return ((names[index] >= 'a') && (names[index] <= 'z')) || + (names[index] == '_') && + this != Names.null_; + } + + public static final Name ERROR = Name.fromString("<error>"); + +/** precedence of this name + */ + public int precedence() { + if (this == ERROR) + return -1; + byte ch = names[index]; + if (((ch >= 'A') && (ch <= 'Z')) || + ((ch >= 'a') && (ch <= 'z'))) + return 1; + switch (ch) { + case '|': + return 2; + case '^': + return 3; + case '&': + return 4; + case '<': + case '>': + return 5; + case '=': + case '!': + return 6; + case ':': + return 7; + case '+': + case '-': + return 8; + case '*': + case '/': + case '%': + return 9; + default: + return 10; + } + } + + public static final int TOP_PRECEDENCE = 11; + +/** is this operator left associative + */ + public boolean leftAssoc() { + return names[index] != ':'; + } +} diff --git a/sources/scalac/util/NameTransformer.java b/sources/scalac/util/NameTransformer.java new file mode 100644 index 0000000000..c9b5e2183f --- /dev/null +++ b/sources/scalac/util/NameTransformer.java @@ -0,0 +1,111 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.util; + +/** A name transformer for replacing operator symbols in names by predefined + * names of the form $opname. + * + * @author Martin Odersky, Christine Roeckl + * @version 1.1 + */ +public class NameTransformer { + + public static String[] operatorName = new String[128]; + + static { + operatorName['~'] = "$tilde"; + operatorName['='] = "$eq"; + operatorName['<'] = "$less"; + operatorName['>'] = "$greater"; + operatorName['!'] = "$bang"; + operatorName['#'] = "$hash"; + operatorName['%'] = "$percent"; + operatorName['^'] = "$up"; + operatorName['&'] = "$amp"; + operatorName['|'] = "$bar"; + operatorName['*'] = "$times"; + operatorName['/'] = "$div"; + operatorName['+'] = "$plus"; + operatorName['-'] = "$minus"; + operatorName[':'] = "$colon"; + } + + /** Replace operator symbols by corresponding "$op_name" in names. + */ + public static Name encode(Name name) { + int i = name.index; + int len = i + name.length(); + StringBuffer res = new StringBuffer(); + while (i < len) { + byte c = Name.names[i++]; + String nop = operatorName[c]; + if (nop == null) + res.append((char)c); + else + res.append(nop); + } + return Name.fromString(res.toString()); + } + + /** Replace "$op_name" by corresponding operator symbols in names. + */ + public static Name decode(Name name) { + int i = name.index; + int length = i + name.length(); + StringBuffer res = new StringBuffer(); + while (i < length) { + byte c = Name.names[i++]; + if ((char)c == '$') { + String op = cutOut(i, length); + res.append(decode("$" + op)); + i = i + op.length(); + } + else res.append((char)c); + } + return Name.fromString(res.toString()); + } + + /** Decodes (a prefix of) a string. + */ + public static String decode(String string) { + for (int i = string.length(); i > 0; i--) { + String prefix = string.substring(0, i); + String c = lookup(prefix); + if (c != null) { + String suffix = string.substring(i, string.length()); + return c + suffix; + } + } + return string; + } + + /** Cuts out the name of an operator plus succeeding characters. + * Does NOT return the preceeding '$' symbol. + */ + private static String cutOut(int pos, int length) { + int i = pos; // avoid side-effects + StringBuffer res = new StringBuffer(); + while (i < length) { + char c = (char)Name.names[i++]; + if (c == '$') return res.toString(); + else res.append(c); + } + return res.toString(); + } + + /** Looks up the array entry for the operator name. + */ + private static String lookup(String string) { + for (int i = 0; i < 128; i++) { + if ((operatorName[i] != null) && (string.compareTo(operatorName[i]) == 0)) + return String.valueOf((char)i); + } + return null; + } +} diff --git a/sources/scalac/util/Names.java b/sources/scalac/util/Names.java new file mode 100644 index 0000000000..a05aad45de --- /dev/null +++ b/sources/scalac/util/Names.java @@ -0,0 +1,98 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** +** $Id$ +\* */ +package scalac.util; + +public class Names { + + public static final Name ERROR = Name.ERROR; + public static final Name EMPTY = Name.EMPTY; + public static final Name WILDCARD = Name.fromString("_"); + public static final Name COMPOUND_NAME = Name.fromString("<ct>"); + public static final Name ANON_CLASS_NAME = Name.fromString("$class"); + + public static final Name _EQ = NameTransformer.encode(Name.fromString("_=")); + public static final Name MINUS = NameTransformer.encode(Name.fromString("-")); + public static final Name PLUS = NameTransformer.encode(Name.fromString("+")); + public static final Name BANG = NameTransformer.encode(Name.fromString("!")); + public static final Name TILDE = NameTransformer.encode(Name.fromString("~")); + public static final Name EQEQ = NameTransformer.encode(Name.fromString("==")); + public static final Name BANGEQ = NameTransformer.encode(Name.fromString("!=")); + public static final Name BARBAR = NameTransformer.encode(Name.fromString("||")); + public static final Name AMPAMP = NameTransformer.encode(Name.fromString("&&")); + public static final Name COLONCOLON = NameTransformer.encode(Name.fromString("::")); + + public static final Name Any = Name.fromString("Any"); + public static final Name AnyVal = Name.fromString("AnyVal"); + public static final Name AnyRef = Name.fromString("AnyRef"); + public static final Name Array = Name.fromString("Array"); + public static final Name Byte = Name.fromString("Byte"); + public static final Name Char = Name.fromString("Char"); + public static final Name Boolean = Name.fromString("Boolean"); + public static final Name Double = Name.fromString("Double"); + public static final Name False = Name.fromString("False"); + public static final Name Float = Name.fromString("Float"); + public static final Name Function = Name.fromString("Function"); + public static final Name Int = Name.fromString("Int"); + public static final Name Long = Name.fromString("Long"); + public static final Name Nil = Name.fromString("Nil"); + public static final Name Object = Name.fromString("Object"); + public static final Name Predef = Name.fromString("Predef"); + public static final Name Short = Name.fromString("Short"); + public static final Name String = Name.fromString("String"); + public static final Name Throwable = Name.fromString("Throwable"); + public static final Name True = Name.fromString("True"); + public static final Name Tuple = Name.fromString("Tuple"); + public static final Name Unit = Name.fromString("Unit"); + public static final Name apply = Name.fromString("apply"); + public static final Name as = Name.fromString("as"); + public static final Name elem = Name.fromString("elem"); + public static final Name filter = Name.fromString("filter"); + public static final Name flatmap = Name.fromString("flatMap"); + public static final Name foreach = Name.fromString("foreach"); + public static final Name hashCode = Name.fromString("hashCode"); + public static final Name is = Name.fromString("is"); + public static final Name java = Name.fromString("java"); + public static final Name java_lang = Name.fromString("java.lang"); + public static final Name java_lang_Object = Name.fromString("java.lang.Object"); + public static final Name java_lang_String = Name.fromString("java.lang.String"); + public static final Name java_lang_Throwable = Name.fromString("java.lang.Throwable"); + public static final Name lang = Name.fromString("lang"); + public static final Name match = Name.fromString("match"); + public static final Name map = Name.fromString("map"); + public static final Name null_ = Name.fromString("null"); + public static final Name predef = Name.fromString("predef"); + public static final Name runtime = Name.fromString("runtime"); + public static final Name scala = Name.fromString("scala"); + public static final Name scala_Algebraic = Name.fromString("scala.Algebraic"); + public static final Name scala_Any = Name.fromString("scala.Any"); + public static final Name scala_AnyRef = Name.fromString("scala.AnyRef"); + public static final Name scala_AnyVal = Name.fromString("scala.AnyVal"); + public static final Name scala_Array = Name.fromString("scala.Array"); + public static final Name scala_Boolean = Name.fromString("scala.Boolean"); + public static final Name scala_Byte = Name.fromString("scala.Byte"); + public static final Name scala_Case = Name.fromString("scala.Case"); + public static final Name scala_Char = Name.fromString("scala.Char"); + public static final Name scala_Double = Name.fromString("scala.Double"); + public static final Name scala_Float = Name.fromString("scala.Float"); + public static final Name scala_Function = Name.fromString("scala.Function"); + public static final Name scala_Int = Name.fromString("scala.Int"); + public static final Name scala_Long = Name.fromString("scala.Long"); + public static final Name scala_Nil = Name.fromString("scala.Nil"); + public static final Name scala_Object = Name.fromString("scala.Object"); + public static final Name scala_Predef = Name.fromString("scala.Predef"); + public static final Name scala_Ref = Name.fromString("scala.Ref"); + public static final Name scala_Short = Name.fromString("scala.Short"); + public static final Name scala_Tuple = Name.fromString("scala.Tuple"); + public static final Name scala_Unit = Name.fromString("scala.Unit"); + public static final Name scala_runtime = Name.fromString("scala.runtime"); + public static final Name toString = Name.fromString("toString"); + public static final Name this_ = Name.fromString("this"); + public static final Name throw_ = Name.fromString("throw"); + public static final Name update = Name.fromString("update"); +} + diff --git a/sources/scalac/util/OptionParser.java b/sources/scalac/util/OptionParser.java new file mode 100644 index 0000000000..01eecb2208 --- /dev/null +++ b/sources/scalac/util/OptionParser.java @@ -0,0 +1,546 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scalac.util; + +import java.text.Format; +import java.text.MessageFormat; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.StringTokenizer; + +import scalac.Main; +import scalac.PhaseDescriptor; +//import scalac.optimizer.OptimizePhase; + +public class CommandParser { + + private final String product; + private final String version; + private final String syntax; + private final Reporter reporter; + private final List/*<ArgumentParser>*/ parsers; + + public CommandParser(String product, String version, String syntax, + Reporter reporter) + { + this.product = product; + this.version = version; + this.syntax = syntax; + this.reporter = reporter; + this.parsers = new ArrayList(); + } + + public String product() { + return product; + } + + public String version() { + return version; + } + + public String syntax() { + return syntax; + } + + public Reporter reporter() { + return reporter; + } + + public boolean add(ArgumentParser parser) { + return parsers.add(parser); + } + + public void add(int index, ArgumentParser parser) { + parsers.add(index, parser); + } + + public boolean remove(ArgumentParser parser) { + return parsers.remove(parser); + } + + public List parsers() { + return parsers; + } + + public boolean parse(String[] args) { + int errors = reporter.errors(); + for (int i = 0; i < args.length; ) { + for (int j = 0; j < parsers.size(); j++) { + ArgumentParser parser = (ArgumentParser)parsers.get(j); + if (parser.matches(args, i)) { + i = parser.consume(args, i); + break; + } + } + } + return reporter.errors() == errors; + } + + public String getHelpMessage() { + Format format = new MessageFormat(" {0}\t {1}"); + List options = new ArrayList(parsers.size()); + for (int i = 0; i < parsers.size(); i++) { + if (!(parsers.get(i) instanceof OptionParser)) continue; + OptionParser parser = (OptionParser)parsers.get(i); + String option = parser.getHelpMessage(format); + if (option != null) options.add(option); + } + StringBuffer buffer = new StringBuffer(); + buffer.append("usage: ").append(product()); + if (options.size() > 0) buffer.append(" <options>"); + if (syntax != null) buffer.append(' ').append(syntax); + buffer.append(Strings.EOL); + if (options.size() > 0) { + buffer.append("where possible options include:"); + buffer.append(Strings.EOL); + buffer.append(Strings.format(options)); + } + return buffer.toString(); + } + + public void error(String message) { + reporter.error(product + ": " + message); + } + + public void warning(String message) { + reporter.warning(product + ": " + message); + } + + public void note(String message) { + reporter.note(product + ": " + message); + } +} + +public abstract class ArgumentParser { + + public final CommandParser command; + + public ArgumentParser(CommandParser command) { + this.command = command; + } + + public abstract boolean matches(String[] args, int index); + public abstract int consume(String[] args, int index); + +} + +public class UnknownArgumentParser extends ArgumentParser { + + public UnknownArgumentParser(CommandParser command) { + super(command); + } + + public boolean matches(String[] args, int index) { + return true; + } + + public int consume(String[] args, int index) { + command.error("don't known what to do with '" + args[index] + "'"); + return index + 1; + } +} + +public class ScalaFileArgumentParser extends ArgumentParser { + + public final List list; + + public ScalaFileArgumentParser(CommandParser command) { + super(command); + this.list = new ArrayList(); + } + + public boolean matches(String[] args, int index) { + return args[index].endsWith(".scala"); + } + + public int consume(String[] args, int index) { + list.add(args[index]); + return index + 1; + } + + public String[] toArray() { + return (String[])list.toArray(new String[list.size()]); + } +} + +public class ScalaProgramArgumentParser extends ArgumentParser { + + public String main; + public String[] args; + + public ScalaProgramArgumentParser(CommandParser command) { + super(command); + } + + public boolean matches(String[] args, int index) { + return args[index].equals("--"); + } + + public int consume(String[] args, int index) { + if (index + 1 < args.length) { + this.main = args[index + 1]; + this.args = new String[args.length - index - 2]; + System.arraycopy(args, index + 2, this.args, 0, this.args.length); + return args.length; + } else { + command.error("option --: missing module name"); + return args.length; + } + } +} + +public abstract class OptionParser extends ArgumentParser { + + public final String option; + public final String description; + + public OptionParser(CommandParser command, String option, + String description) + { + super(command); + this.option = option; + this.description = description; + } + + public String getHelpSyntax() { + return "-" + option; + } + + public String getHelpDescription() { + return description; + } + + public void getHelpMessageArgs(List args) { + args.add(getHelpSyntax()); + args.add(getHelpDescription()); + } + + public String getHelpMessage(Format format) { + if (description == null) return null; + List args = new ArrayList(); + getHelpMessageArgs(args); + return format.format(args.toArray()); + } + + public void error(String message) { + command.error("option -" + option + ": " + message); + } + + public void warning(String message) { + command.warning("option -" + option + ": " + message); + } + + public void note(String message) { + command.note("option -" + option + ": " + message); + } +} +/* +public class OptimizeOptionParser extends OptionParser { + + private final OptimizePhase optimizer; + public boolean optimize; + + public OptimizeOptionParser(CommandParser command, + String option, String description, OptimizePhase optimizer) + { + super(command, option, description); + this.optimizer = optimizer; + this.optimize = false; + } + + public boolean matches(String[] args, int index) { + return args[index].equals("-" + option); + } + + public int consume(String[] args, int index) { + optimizer.setOptions(args[index].substring(1 + option.length())); + optimize = true; + return index + 1; + } + + public String getHelpSyntax() { + return super.getHelpSyntax() + "[:<options>]"; + } +} +*/ +public class VersionOptionParser extends OptionParser { + + private final String version; + + public VersionOptionParser(CommandParser command, + String option, String description, String version) + { + super(command, option, description); + this.version = version; + } + + public boolean matches(String[] args, int index) { + return args[index].equals("-" + option); + } + + public int consume(String[] args, int index) { + System.out.println(version); + System.exit(0); + return index + 1; + } +} + +public class HelpOptionParser extends OptionParser { + + public HelpOptionParser(CommandParser command, + String option, String description) + { + super(command, option, description); + } + + public boolean matches(String[] args, int index) { + return args[index].equals("-?") || + args[index].equals("-" + option) || + args[index].equals("--" + option); + } + + public int consume(String[] args, int index) { + System.out.println(command.getHelpMessage()); + System.exit(0); + return index + 1; + } + + public String getHelpSyntax() { + return "-? " + super.getHelpSyntax(); + } +} + +public class UnknownOptionParser extends OptionParser { + + public UnknownOptionParser(CommandParser command) { + super(command, "", null); + } + + public boolean matches(String[] args, int index) { + return args[index].startsWith("-"); + } + + public int consume(String[] args, int index) { + command.error("unknown option " + args[index]); + return index + 1; + } +} + +public class BooleanOptionParser extends OptionParser { + + public boolean value; + + public BooleanOptionParser(CommandParser command, + String option, String description, boolean value) + { + super(command, option, description); + this.value = value; + } + + public boolean matches(String[] args, int index) { + return args[index].equals("-" + option); + } + + public int consume(String[] args, int index) { + value = true; + return index + 1; + } +} + +public class StringOptionParser extends OptionParser { + + public String value; + public String argument; + + public StringOptionParser(CommandParser command, + String option, String description, String argument, String value) + { + super(command, option, description); + this.argument = argument; + this.value = value; + } + + public boolean matches(String[] args, int index) { + return args[index].equals("-" + option); + } + + public int consume(String[] args, int index) { + if (index + 1 < args.length) { + value = args[index + 1]; + return index + 2; + } else { + error("missing argument"); + return index + 1; + } + } + + public String getHelpSyntax() { + String syntax = super.getHelpSyntax(); + if (argument != null) syntax = syntax + " <" + argument + ">"; + return syntax; + } +} + +public class PhaseSetOptionParser extends OptionParser { + + private final PhaseDescriptor[] phases; + private final int flag; + private final PrefixMatcher matcher; + + public PhaseSetOptionParser(CommandParser command, + String option, String description, PhaseDescriptor[] phases, int flag) + { + super(command, option, description); + this.phases = phases; + this.flag = flag; + this.matcher = new PrefixMatcher(); + for (int i = 0; i < phases.length; i++) { + PhaseDescriptor phase = phases[i]; + matcher.insert(phase.name(), phase, phase.description()); + } + } + + public boolean matches(String[] args, int index) { + return args[index].startsWith("-" + option + ":"); + } + + public int consume(String[] args, int index) { + StringTokenizer tokens = new StringTokenizer( + args[index].substring(option.length() + 2), ","); + while (tokens.hasMoreTokens()) consumePhase(tokens.nextToken()); + return index + 1; + } + + public void consumePhase(String token) { + if (token.equals("all")) { + for (int i = 0; i < phases.length; i++) phases[i].flags |= flag; + return; + } + PhaseDescriptor phase = lookup(getPhaseName(token)); + if (phase != null) { + boolean before = getBeforeFlag(token); + boolean after = getAfterFlag(token) || !before; + if (before) phase.flags |= flag << 16; + if (after) phase.flags |= flag; + } + } + + public PhaseDescriptor lookup(String name) { + if (name.length() == 0) { + error("illegal zero-length phase name"); + return null; + } + PrefixMatcher.Entry[] entries = matcher.lookup(name); + if (entries.length == 1) return (PhaseDescriptor)entries[0].value; + error(matcher.getErrorMessage(name, entries, "phase name")); + return null; + } + + public boolean getBeforeFlag(String token) { + for (int i = token.length(); 0 < i--; ) { + switch (token.charAt(i)) { + case '-': return true; + case '+': continue; + default : return false; + } + } + return false; + } + + public boolean getAfterFlag(String token) { + for (int i = token.length(); 0 < i--; ) { + switch (token.charAt(i)) { + case '-': continue; + case '+': return true; + default : return false; + } + } + return false; + } + + public String getPhaseName(String token) { + for (int i = token.length(); 0 < i--; ) { + switch (token.charAt(i)) { + case '-': continue; + case '+': continue; + default : return token.substring(0, i + 1); + } + } + return ""; + } + + public String getHelpSyntax() { + return super.getHelpSyntax() + ":<phases>"; + } +} + +public class PrintOptionParser extends PhaseSetOptionParser { + + public boolean tokens; + + public PrintOptionParser(CommandParser command, + String option, String description, PhaseDescriptor[] phases, int flag) + { + super(command, option, description, phases, flag); + this.tokens = false; + } + + public void consumePhase(String token) { + if ("tokens".equals(token)) + tokens = true; + else + super.consumePhase(token); + } + +} + +public class ChoiceOptionParser extends OptionParser { + + public final String argument; + public final String[] choices; + + public String value; + + public ChoiceOptionParser(CommandParser command, + String option, String description, String argument, String[] choices, + String value) + { + super(command, option, description); + this.argument = argument; + this.choices = choices; + this.value = value; + } + + public boolean matches(String[] args, int index) { + return args[index].startsWith("-" + option + ":"); + } + + public int consume(String[] args, int index) { + String choice = args[index].substring(option.length() + 2); + boolean found = false; + for (int i = 0; i < choices.length; i++) { + if (choices[i].equals(choice)) { found = true; break; } + } + if (found) { + value = choice; + } else if (choice.length() > 0) { + error("unknown " + argument + " '" + choice + "'"); + } else { + error("missing " + argument); + } + return index + 1; + } + + public String getHelpSyntax() { + String syntax = super.getHelpSyntax(); + if (argument != null) syntax = syntax + ":<" + argument + ">"; + return syntax; + } +} diff --git a/sources/scalac/util/Position.java b/sources/scalac/util/Position.java new file mode 100644 index 0000000000..c2cd7f72d3 --- /dev/null +++ b/sources/scalac/util/Position.java @@ -0,0 +1,54 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.util; + + +public final class Position { + +/** source file positions are integers in the format: + * line-number << LINESHIFT + column-number + * NOPOS represents an undefined position. + */ + public static final int LINESHIFT = 10; + public static final int FILESHIFT = 26; + public static final int COLUMNMASK = 1023; + public static final int LINEMASK = 0xffff; + +/** predefined positions + */ + public static final int NOPOS = 0; + +/** first position in a source file + */ + public static final int FIRSTPOS = (1 << LINESHIFT) + 1; + +/** encode a line and column number into a single int + */ + public static int encode(int line, int col, int file) { + return (file << FILESHIFT) | (line << LINESHIFT) | col; + } + +/** get the file id of an encoded position + */ + public static int file(int pos) { + return pos >>> FILESHIFT; + } + +/** get the line number out of an encoded position + */ + public static int line(int pos) { + return (pos >>> LINESHIFT) & LINEMASK; + } + +/** return the column number of an encoded position + */ + public static int column(int pos) { + return pos & COLUMNMASK; + } +} diff --git a/sources/scalac/util/PrefixMatcher.java b/sources/scalac/util/PrefixMatcher.java new file mode 100644 index 0000000000..1b0acd8d7a --- /dev/null +++ b/sources/scalac/util/PrefixMatcher.java @@ -0,0 +1,114 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scalac.util; + +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; + +public class PrefixMatcher { + + public static class Entry { + + private Entry prev; + private Entry next; + + public final String key; + public final Object value; + public final String argument; + public final String description; + + public Entry(String key, Object value, String argument, + String description) + { + this.key = key; + this.value = value; + this.argument = argument; + this.description = description; + } + } + + private final Map entries; + private Entry first; + private Entry last; + + public PrefixMatcher() { + this.entries = new HashMap(); + } + + public void insert(String key, Object value) { + insert(key, value, null, null); + } + + public void insert(String key, Object value, String description) { + insert(key, value, null, description); + } + + public void insert(String key, Object value, String argument, + String description) + { + assert key != null && !entries.containsKey(key) : key; + Entry entry = new Entry(key, value, argument, description); + if (first == null) { + first = last = entry; + } else { + last.next = entry; + entry.prev = last; + last = entry; + } + entries.put(key, entry); + } + + public Entry[] lookup(String key) { + Object value = entries.get(key); + if (value != null) return new Entry[] { (Entry)value }; + List list = new ArrayList(); + for (Entry i = first; i != null; i = i.next) { + if (i.key.startsWith(key)) list.add(i); + } + return (Entry[])list.toArray(new Entry[list.size()]); + } + + public String getErrorMessage(String key, Entry[] entries, String what) { + switch (entries.length) { + case 0: + return "unknown " + what + " '" + key + "'"; + case 1: + return null; + case 2: + return "ambigous " + what + " '" + key + "', both '" + + entries[0].key + "' and '" + entries[1].key + "' match"; + default: + StringBuffer buffer = new StringBuffer(); + buffer.append("ambigous ").append(what); + buffer.append(" '").append(key).append("'"); + for (int i = 0; i < entries.length; i++) { + buffer.append(i < entries.length - 1 ? ", " : " and "); + buffer.append('\'').append(entries[i].key).append('\''); + } + buffer.append(" match"); + return buffer.toString(); + } + } + + public List getHelpStrings(String separator1, String separator2) { + List strings = new ArrayList(); + for (Entry entry = first; entry != null; entry = entry.next) { + if (entry.description != null) + if (entry.argument != null) + strings.add(entry.key + separator1 + entry.argument + + separator2 + entry.description); + else + strings.add(entry.key + separator2 + entry.description); + } + return strings; + } + +} diff --git a/sources/scalac/util/Reporter.java b/sources/scalac/util/Reporter.java new file mode 100644 index 0000000000..a1fb832e28 --- /dev/null +++ b/sources/scalac/util/Reporter.java @@ -0,0 +1,192 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scalac.util; + +import java.io.InputStreamReader; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.IOException; +import scalac.ApplicationError; + +public class Reporter { + + //######################################################################## + // Private state + + private final BufferedReader reader; + private final PrintWriter writer; + + /** Number of errors issued totally */ + private int errors; + /** Number of warning issued totally */ + private int warnings; + /** Number of notes issued totally */ + private int notes; + + //######################################################################## + // Reporter constructors + + public Reporter() { + this( + new BufferedReader(new InputStreamReader(System.in)), + new PrintWriter(System.err, true)); + } + + public Reporter(BufferedReader reader, PrintWriter writer) { + this.reader = reader; + this.writer = writer; + this.prompt = false; + this.nowarn = false; + this.verbose = false; + this.errors = 0; + this.notes = 0; + } + + //######################################################################## + // Reporter state + + /** Whether warnings should be issued */ + public boolean nowarn; + /** Whether notes and information messages should be issued */ + public boolean verbose; + /** Whether a prompt should be displayed after errors and warnings */ + public boolean prompt; + + //######################################################################## + // Reporter interface - query + + /** Return the number of errors issued totally */ + public int errors() { + return errors; + } + + /** Return the number of warnings issued totally */ + public int warnings() { + return warnings; + } + + /** Return the number of notes issued totally */ + public int notes() { + return notes; + } + + /** Return the number of errors issued totally as a string */ + public String getErrorCountString() { + return getCountString(errors, "error"); + } + + /** Return the number of warnings issued totally as a string */ + public String getWarningCountString() { + return getCountString(warnings, "warning"); + } + + /** Return the number of notes issued totally as a string */ + public String getNoteCountString() { + return getCountString(notes, "note"); + } + + public String getCountString(int count, String what) { + switch (count) { + case 0: return "no " + what + "s"; + case 1: return "one " + what; + case 2: return "two " + what + "s"; + case 3: return "three " + what + "s"; + case 4: return "four " + what + "s"; + default: return count + " " + what + "s"; + } + } + + //######################################################################## + // Reporter interface - report + + /** Reset all counters */ + public void resetCounters() { + errors = 0; + warnings = 0; + notes = 0; + } + + /** Issue a message */ + public void report(String message) { + writer.println(message); + } + + /** Issue a message */ + public void inform(String message) { + if (verbose) report(message); + } + + /** Issue an error */ + public void error(String message) { + error(message, false); + } + + /** Issue an error if it is not hidden */ + public void error(String message, boolean hidden) { + if (!hidden || prompt) report(message); + if (!hidden) errors++; + if (prompt) failOnDemand(); + } + + /** Issue a warning */ + public void warning(String message) { + warning(message, false); + } + + /** Issue a warning if it is not hidden */ + public void warning(String message, boolean hidden) { + if (nowarn) return; + if (!hidden || prompt) report(message); + if (!hidden) warnings++; + if (prompt) failOnDemand(); + } + + /** Issue a note */ + public void note(String message) { + note(message, false); + } + + /** Issue a note if it is not hidden */ + public void note(String message, boolean hidden) { + if (!hidden) report(message); + if (!hidden) notes++; + } + + public void printSummary() { + if (errors() > 0) report(getErrorCountString() + " found"); + if (warnings() > 0) report(getWarningCountString() + " found"); + if (notes() > 0) report(getNoteCountString() + " found"); + } + + //######################################################################## + // Reporter interface - fail + + /** Fail only if requested */ + public void failOnDemand() { + failOnDemand("user abort"); + } + + /** Fail only if requested */ + public void failOnDemand(String message) { + try { + while (true) { + writer.print("r)esume, a)bort: "); + String line = reader.readLine(); + if (line == null) continue; else line = line.toLowerCase(); + if ("abort".startsWith(line)) + throw new ApplicationError(message); + if ("resume".startsWith(line)) return; + } + } catch (IOException e) { + throw new ApplicationError("input read error"); + } + } + + //######################################################################## +} diff --git a/sources/scalac/util/SourceRepresentation.java b/sources/scalac/util/SourceRepresentation.java new file mode 100644 index 0000000000..7c6ee44107 --- /dev/null +++ b/sources/scalac/util/SourceRepresentation.java @@ -0,0 +1,205 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id +\* */ + +package scalac.util; + +public final class SourceRepresentation { + + public static int digit2int(byte ch, int base) { + if ('0' <= ch && ch <= '9' && ch < '0' + base) + return ch - '0'; + else if ('A' <= ch && ch < 'A' + base - 10) + return ch - 'A' + 10; + else if ('a' <= ch && ch < 'a' + base - 10) + return ch - 'a' + 10; + else + return -1; + } + + public static byte int2digit(int x) { + if (x <= 9) + return (byte)(x + '0'); + else + return (byte)(x - 10 + 'A'); + } + +/* the next 4 functions convert between three fundamental name + * representations: + * - string each character 16 bit, + * - source characters outside 0..127 are represented by + * unicode escapes, \ u X X X X + * - ascii characters outside 0..127 are represented by two or three + * byte sequences with high bit set (as in class file format). + */ + +/** convert source bytes in source[offset..offset+len-1] to ascii. + */ + public static int source2ascii(byte source[], int offset, int len, byte ascii[]) { + int j = 0; + int i = 0; + while (i < len) { + if (source[offset + i] == '\\' && i + 1 < len) { + i++; + switch (source[offset + i]) { + case 'n': + ascii[j++] = (byte)'\n'; i++; continue; + case 't': + ascii[j++] = (byte)'\t'; i++; continue; + case 'b': + ascii[j++] = (byte)'\b'; i++; continue; + case 'r': + ascii[j++] = (byte)'\r'; i++; continue; + case 'f': + ascii[j++] = (byte)'\f'; i++; continue; + case 'u': + if (i + 4 < len) { + int code = 0; + int k = 1; + int d = 0; + while (k <= 4 && d >= 0) { + d = digit2int(source[offset + i + k], 16); + code = code * 16 + d; + k++; + } + if (d >= 0) { + if (code <= 0x7F) + ascii[j++] = (byte)code; + else + if (code <= 0x3FF) { + ascii[j++] = (byte)(0xC0 | (code >> 6)); + ascii[j++] = (byte)(0x80 | (code & 0x3F)); + } else { + ascii[j++] = (byte)(0xE0 | (code >> 12)); + ascii[j++] = (byte)(0x80 | + ((code >> 6) & 0x3F)); + ascii[j++] = (byte)(0x80 | (code & 0x3F)); + } + i = i + 5; + continue; + } + } + } + } + byte b = source[offset + i++]; + if (b >= 0) + ascii[j++] = b; + else { + ascii[j++] = (byte)(0xC0 | ((b >> 6) & 0x3)); + ascii[j++] = (byte)(0x80 | (b & 0x3F)); + } + } + return j; + } + +/** convert ascii bytes in ascii[offset..offset+len-1] to a string + */ + public static String ascii2string(byte ascii[], int offset, int len) { + char cs[] = new char[len]; + int i = offset; + int j = 0; + len += offset; + while (i < len) { + int b = ascii[i++] & 0xFF; + if (b >= 0xE0) { + b = ((b & 0x0F) << 12) | (ascii[i++] & 0x3F) << 6; + b = b | (ascii[i++] & 0x3F); + } + else + if (b >= 0xC0) + b = ((b & 0x1F) << 6) | (ascii[i++] & 0x3F); + cs[j++] = (char)b; + } + return new String(cs, 0, j); + } + +/** convert string to array of source bytes + */ + public static byte[] string2source(String s) { + byte[] source = new byte[s.length() * 6]; + int j = 0; + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + switch (ch) { + case '\n': + source[j++] = (byte)'\\'; + source[j++] = (byte)'n'; + break; + case '\t': + source[j++] = (byte)'\\'; + source[j++] = (byte)'t'; + break; + case '\b': + source[j++] = (byte)'\\'; + source[j++] = (byte)'b'; + break; + case '\r': + source[j++] = (byte)'\\'; + source[j++] = (byte)'r'; + break; + case '\f': + source[j++] = (byte)'\\'; + source[j++] = (byte)'f'; + break; + case '\"': + source[j++] = (byte)'\\'; + source[j++] = (byte)'\"'; + break; + case '\'': + source[j++] = (byte)'\\'; + source[j++] = (byte)'\''; + break; + case '\\': + source[j++] = (byte)'\\'; + source[j++] = (byte)'\\'; + break; + default: + if ((' ' <= ch) && (ch <= 127)) + source[j++] = (byte)ch; + else { + source[j++] = (byte)'\\'; + source[j++] = (byte)'u'; + source[j++] = int2digit((ch >> 12) & 0xF); + source[j++] = int2digit((ch >> 8) & 0xF); + source[j++] = int2digit((ch >> 4) & 0xF); + source[j++] = int2digit(ch & 0xF); + } + } + } + byte[] res = new byte[j]; + System.arraycopy(source, 0, res, 0, j); + return res; + } + +/** convert string to array of ascii bytes + */ + public static byte[] string2ascii(String s) { + byte[] source = string2source(s); + byte[] ascii = new byte[source.length * 2]; + int alen = source2ascii(source, 0, source.length, ascii); + byte[] res = new byte[alen]; + System.arraycopy(ascii, 0, res, 0, alen); + return res; + } + +/** escape all characters outside 32..127 in string s + */ + public static String escape(String s) { + try { + return new String(string2source(s), "8859_1"); + } catch (java.io.UnsupportedEncodingException e) { + throw new InternalError(e.getMessage()); + } + } + +/** escape character c, if outside 32..127. + */ + public static String escape(char c) { + char[] s = {c}; + return escape(new String(s)); + } +} diff --git a/sources/scalac/util/Strings.java b/sources/scalac/util/Strings.java new file mode 100644 index 0000000000..540a61020e --- /dev/null +++ b/sources/scalac/util/Strings.java @@ -0,0 +1,102 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scalac.util; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; + +public abstract class Strings { + + //######################################################################## + // Strings constants + + final public static String[] NONE = new String[0]; + + //######################################################################## + // Strings interface + + /** The line separator */ + public static String EOL = System.getProperty("line.separator", "\n"); + + /** Returns a string where all tabs have been replaced by white + * spaces to make the corresponding fields the same width. + */ + public static String format(List strings) { + List[] lines = new List[strings.size()]; + List widths = new ArrayList(); + int height = 0; + for (Iterator iterator = strings.iterator(); iterator.hasNext(); ) { + String string = (String)iterator.next(); + List line = lines[height++] = new ArrayList(); + for (int last = 0; last < string.length(); ) { + int next = string.indexOf('\t', last); + if (next < 0) next = string.length(); + String substring = string.substring(last, next); + int index = line.size(); + if (index == widths.size()) widths.add(new Integer(0)); + int width = ((Integer)widths.get(index)).intValue(); + widths.set( + index, new Integer(Math.max(width, substring.length()))); + line.add(substring); + last = next + 1; + } + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < lines.length; i++) { + List line = lines[i]; + for (int j = 0; true; j++) { + String string = (String)line.get(j); + buffer.append(string); + if (j == line.size() - 1) break; + int width = ((Integer)widths.get(j)).intValue(); + for (int k = string.length(); k<width; k++) buffer.append(' '); + } + buffer.append(EOL); + } + return buffer.toString(); + } + + /** Returns the first char of the string or -1 if the string is empty. */ + public static int firstChar(String string) { + return string.length() == 0 ? -1 : string.charAt(0); + } + + /** Returns the last char of the string or -1 if the string is empty. */ + public static int lastChar(String string) { + return string.length() == 0 ? -1 : string.charAt(string.length() - 1); + } + + /** Returns a copy of the string, with leading whitespace omitted. */ + public static String trimLeading(String string) { + for (int i = 0; i < string.length(); i++) + if (string.charAt(i) > ' ') return string.substring(i); + return ""; + } + + /** Returns a copy of the string, with trailing whitespace omitted. */ + public static String trimTrailing(String string) { + for (int i = string.length() - 1; i >= 0; i--) + if (string.charAt(i) > ' ') return string.substring(0, i + 1); + return ""; + } + + /** Returns the stack trace of the exception */ + public static String stackTrace(Throwable exception) { + StringWriter buffer = new StringWriter(); + PrintWriter writer = new PrintWriter(buffer); + exception.printStackTrace(writer); + writer.close(); + return buffer.toString(); + } + + //######################################################################## +} diff --git a/sources/scalac/util/UniqueID.java b/sources/scalac/util/UniqueID.java new file mode 100644 index 0000000000..59e31a9de6 --- /dev/null +++ b/sources/scalac/util/UniqueID.java @@ -0,0 +1,30 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $Id$ + +package scalac.util; + +import java.util.*; + +/** + * Class to assign unique and small numbers to objects, based on their + * identity. + * + * @author Michel Schinz + * @version 1.0 + */ + +public class UniqueID { + protected Map ids = new HashMap(); + + public int id(Object obj) { + if (! ids.containsKey(obj)) + ids.put(obj, new Integer(ids.size())); + return ((Integer)ids.get(obj)).intValue(); + } +} |