/*
* xtc - The eXTensible Compiler
* Copyright (C) 2006-2007 Robert Grimm
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package xtc.type;
import java.io.IOException;
import xtc.Limits;
/**
* The superclass of all number types.
*
* @author Robert Grimm
* @version $Revision: 1.27 $
*/
public abstract class NumberT extends Type {
/** The number kind. */
public static enum Kind {
/** A signed byte. */
BYTE,
/** A char. */
CHAR,
/** A signed char. */
S_CHAR,
/** An unsigned char. */
U_CHAR,
/** A signed short. */
SHORT,
/** An unsigned short. */
U_SHORT,
/**
* An int. Per C99 6.7.2, it depends on the implementation
* whether <code>int</code> appearing by itself in a bit-field is
* signed or unsigned. Hence we distinguish between ints and
* signed ints. (Whatever.)
*/
INT,
/** A signed int. */
S_INT,
/** An unsigned int. */
U_INT,
/** A signed long. */
LONG,
/** An unsigned long. */
U_LONG,
/** A signed long long. */
LONG_LONG,
/** An unsigned long long. */
U_LONG_LONG,
/** A float. */
FLOAT,
/** A double. */
DOUBLE,
/** A long double. */
LONG_DOUBLE,
/** A float complex. */
FLOAT_COMPLEX,
/** A double complex. */
DOUBLE_COMPLEX,
/** A long double complex. */
LONG_DOUBLE_COMPLEX
}
// =========================================================================
/** The canonical signed byte type. */
public static final IntegerT BYTE = new IntegerT(Kind.BYTE);
/** The canonical char type. */
public static final IntegerT CHAR = new IntegerT(Kind.CHAR);
/** The canonical signed char type. */
public static final IntegerT S_CHAR = new IntegerT(Kind.S_CHAR);
/** The canonical unsigned char type. */
public static final IntegerT U_CHAR = new IntegerT(Kind.U_CHAR);
/** The canonical short type. */
public static final IntegerT SHORT = new IntegerT(Kind.SHORT);
/** The canonical unsigned short type. */
public static final IntegerT U_SHORT = new IntegerT(Kind.U_SHORT);
/** The canonical int type. */
public static final IntegerT INT = new IntegerT(Kind.INT);
/** The canonical signed int type. */
public static final IntegerT S_INT = new IntegerT(Kind.S_INT);
/** The cannical unsigned int type. */
public static final IntegerT U_INT = new IntegerT(Kind.U_INT);
/** The canonical signed long type. */
public static final IntegerT LONG = new IntegerT(Kind.LONG);
/** The canonical unsigned long type. */
public static final IntegerT U_LONG = new IntegerT(Kind.U_LONG);
/** The canonical signed long long type. */
public static final IntegerT LONG_LONG = new IntegerT(Kind.LONG_LONG);
/** The canonical unsigned long long type. */
public static final IntegerT U_LONG_LONG = new IntegerT(Kind.U_LONG_LONG);
/** The canonical float type. */
public static final FloatT FLOAT = new FloatT(Kind.FLOAT);
/** The canonical double type. */
public static final FloatT DOUBLE = new FloatT(Kind.DOUBLE);
/** The canonical long double type. */
public static final FloatT LONG_DOUBLE = new FloatT(Kind.LONG_DOUBLE);
/** The canonical float complex type. */
public static final FloatT FLOAT_COMPLEX = new FloatT(Kind.FLOAT_COMPLEX);
/** The canonical double complex type. */
public static final FloatT DOUBLE_COMPLEX = new FloatT(Kind.DOUBLE_COMPLEX);
/** The canonical long double complex type. */
public static final FloatT LONG_DOUBLE_COMPLEX =
new FloatT(Kind.LONG_DOUBLE_COMPLEX);
static {
BYTE.seal();
CHAR.seal();
S_CHAR.seal();
U_CHAR.seal();
SHORT.seal();
U_SHORT.seal();
INT.seal();
S_INT.seal();
U_INT.seal();
LONG.seal();
U_LONG.seal();
LONG_LONG.seal();
U_LONG_LONG.seal();
FLOAT.seal();
DOUBLE.seal();
LONG_DOUBLE.seal();
FLOAT_COMPLEX.seal();
DOUBLE_COMPLEX.seal();
LONG_DOUBLE_COMPLEX.seal();
}
// =========================================================================
/** The kind. */
protected final Kind kind;
/**
* Create a new number type. The specified kind must be a valid
* integer or float kind.
*
* @param kind The kind.
*/
public NumberT(Kind kind) {
this.kind = kind;
}
/**
* Create a new number type. The specified kind must be a valid
* integer or float kind.
*
* @param template The type whose annotations to copy.
* @param kind The kind.
*/
public NumberT(Type template, Kind kind) {
super(template);
this.kind = kind;
}
public boolean isNumber() {
return true;
}
public NumberT toNumber() {
return this;
}
/**
* Determine whether this number has the specified kind. Note that
* this method uses {@link #equal(Kind,Kind)} to perform the kind
* comparison.
*
* @param kind The kind.
* @return <code>true</code> if this number has the specified kind.
*/
public boolean hasKind(Kind kind) {
return equal(this.kind, kind);
}
/**
* Get the kind.
*
* @return The kind.
*/
public Kind getKind() {
return kind;
}
/**
* Determine whether this number is signed.
*
* @return <code>true</code> if this number is signed.
*/
public boolean isSigned() {
switch (kind) {
case U_CHAR:
case U_SHORT:
case U_INT:
case U_LONG:
case U_LONG_LONG:
return false;
case CHAR:
return Limits.IS_CHAR_SIGNED;
default:
return true;
}
}
public int hashCode() {
return (kind.ordinal() + 1) * 37;
}
/**
* Determine whether this type equals the specified object. This
* number equals the specified object if the specified object also
* is a number and the two numbers' kinds are either the same or a
* combination of the {@link Kind#INT int} and {@link Kind#S_INT
* signed int} kinds.
*
* @param o The object.
* @return <code>true</code> if this type equals the object.
*/
public boolean equals(Object o) {
if (! (o instanceof Type)) return false;
Type t = resolve(o);
if (this == t) return true;
if (! t.isNumber()) return false;
return equal(kind, ((NumberT)t).kind);
}
public void write(Appendable out) throws IOException {
out.append(toString());
}
public String toString() {
switch (kind) {
case BYTE:
return "byte";
case CHAR:
return "char";
case S_CHAR:
return "signed char";
case U_CHAR:
return "unsigned char";
case SHORT:
return "short";
case U_SHORT:
return "unsigned short";
case INT:
return "int";
case S_INT:
return "signed int";
case U_INT:
return "unsigned int";
case LONG:
return "long";
case U_LONG:
return "unsigned long";
case LONG_LONG:
return "long long";
case U_LONG_LONG:
return "unsigned long long";
case FLOAT:
return "float";
case DOUBLE:
return "double";
case LONG_DOUBLE:
return "long double";
case FLOAT_COMPLEX:
return "float _Complex";
case DOUBLE_COMPLEX:
return "double _Complex";
case LONG_DOUBLE_COMPLEX:
return "long double _Complex";
default:
throw new AssertionError("Invalid kind: " + kind);
}
}
// =========================================================================
/**
* Determine whether the specified kinds equal each other. This
* method treats implicit, int, and signed int types as equal.
*
* @param k1 The first kind.
* @param k2 The second kind.
* @return <code>true</code> if the kinds are equal.
*/
public static boolean equal(Kind k1, Kind k2) {
return ((k1 == k2) ||
(((Kind.INT == k1) || (Kind.S_INT == k1)) &&
((Kind.INT == k2) || (Kind.S_INT == k2))));
}
/**
* Determine whether the specified kinds equal each other, modulo
* their signs. This method treats implicit, int, and signed int
* types as equal.
*
* @param k1 The first kind.
* @param k2 The second kind.
* @return <code>true</code> if the kinds are equal modulo their
* signs.
*/
public static boolean equalIgnoringSign(Kind k1, Kind k2) {
switch (k1) {
case CHAR:
case S_CHAR:
case U_CHAR:
return (Kind.CHAR == k2) || (Kind.S_CHAR == k2) || (Kind.U_CHAR == k2);
case SHORT:
case U_SHORT:
return (Kind.SHORT == k2) || (Kind.U_SHORT == k2);
case INT:
case S_INT:
case U_INT:
return (Kind.INT == k2) || (Kind.S_INT == k2) || (Kind.U_INT == k2);
case LONG:
case U_LONG:
return (Kind.LONG == k2) || (Kind.U_LONG == k2);
case LONG_LONG:
case U_LONG_LONG:
return (Kind.LONG_LONG == k2) || (Kind.U_LONG_LONG == k2);
default:
return (k1 == k2);
}
}
}