/* ____ ____ ____ ____ ______ *\
** / __// __ \/ __// __ \/ ____/ 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];
/** 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;
}
/** 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() {
if (this == ERROR) return true;
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() {
if (this == ERROR) return true;
int h = hashValue(names, index, len) & HASH_MASK;
Name n = typeHashtable[h];
while (n != null && n != this)
n = n.next;
return n == this;
}
/** create a term name corresponding to this name
*/
public Name toTermName() {
if (this == ERROR) return this;
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() {
if (this == ERROR) return this;
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;
}
/** 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_ &&
this != Names.true_ &&
this != Names.false_;
}
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 isLeftAssoc() {
return names[index + len -1] != ':';
}
}