view sema/DType.d @ 179:2a1a635bd531

Changes the way messages can be displayed. Also added a toString to DType's for type printing.
author Anders Johnsen <skabet@gmail.com>
date Fri, 25 Jul 2008 01:21:07 +0200
parents dc9bf56b7ace
children 59cd211a1bd3
line wrap: on
line source

module sema.DType;

import lexer.Token,
       ast.Exp;

public
import sema.Operation;

///
class DType
{
    private char[] id;
    private SourceLocation loc;
    public DType actual;

    this(Identifier id, DType actual = null)
    {
        this.id = id.name;
        this.loc = id.startLoc();
        this.actual = actual is null? this : actual;
    }

    this(char[] id, DType actual = null)
    {
        this.id = id;
        this.actual = actual is null? this : actual;
    }

    /// Is this type a DStruct
    bool isStruct() { return false; }
    /// Return a DStruct if this is one, otherwise return null
    DStruct asStruct() { return null; }

    /// Is this type a DClass
    bool isClass() { return false; }
    /// Return a DClass if this is one, otherwise return null
    DClass asClass() { return null; }

    /// Is this type a DInterface
    bool isInterface() { return false; }
    /// Return a DInterface if this is one, otherwise return null
    DInterface asInterface() { return null; }

    /// Is this type a DStaticArray
    bool isStaticArray() { return false; }
    /// Return a DStaticArray if this is one, otherwise return null
    DStaticArray asStaticArray() { return null; }

    /// Is this type a DArray
    bool isArray() { return false; }
    /// Return a DArray if this is one, otherwise return null
    DArray asArray() { return null; }

    /// Is this type a DPointer
    bool isPointer() { return false; }
    /// Return a DPointer if this is one, otherwise return null
    DPointer asPointer() { return null; }

    /// Is this type a DFunction
    bool isFunction() { return false; }
    /// Return a DFunction if this is one, otherwise return null
    DFunction asFunction() { return null; }

    /// Returns true for integers, reals and complex numbers
    bool isArithmetic() { return false; }

    /// Is this type a DInteger
    bool isInteger() { return false; }
    /// Return a DInteger if this is one, otherwise return null
    DInteger asInteger() { return null; }

    /// Is this type a DReal
    bool isReal() { return false; }
    /// Return a DReal if this is one, otherwise return null
    DReal asReal() { return null; }

    int opEquals(Object o)
    {
        if (auto t = cast(DType)o)
            return this.actual is t.actual;
        return 0;
    }

    int opCmp(Object o)
    {
        if (auto t = cast(DType)o)
            return cast(void*)this.actual - cast(void*)t.actual;
        return 0;
    }

    /**
      Hashing is done by casting the reference to a void* and taking that
      value, but this gives a bad distribution of hash-values.

      Multiple DType's allocated close to each other will only have a
      difference in the lower bits of their hashes.
     */
    hash_t toHash()
    {
        return cast(hash_t)(cast(void*)this);
    }

    char[] toString()
    {
        return id;
    }

    char[] name() { return id; }
    SourceLocation getLoc() { return loc; }
    int byteSize() { return 0; }

    /**
      Can this type legally be converted to that type with no casts?
      True for short -> int etc.
     */
    bool hasImplicitConversionTo(DType that) { return false; }

    /**
      Get an Operation describing how to use the supplied operator on the two
      types given.
     */
    Operation getOperationWith(Operator op, DType other)
    {
        Operation res;
        return res;
    }

    /**
      Get a type representing a pointer to this type (from int to int*)
     */
    DPointer getPointerTo()
    {
        if(myPointer !is null)
            return myPointer;
        myPointer = new DPointer(this);
        return myPointer;
    }
    private DPointer myPointer;

    /** 
      Mangle the DType following the specs at http://digitalmars.com/d/1.0/abi.html
     **/
    char[] mangle()
    {
        /// expects to be void
        return "v";
    }

    /**
      Get a type representing a static array of this type with length 'size'
     */
    DStaticArray getAsStaticArray(int size)
    {
        if(size in myStaticArray)
            return myStaticArray[size];
        myStaticArray[size] = new DStaticArray(this, size);
        return myStaticArray[size];
    }
    private DStaticArray[int] myStaticArray;

    DArray getAsArray()
    {
        if(myArray !is null)
            return myArray;
        myArray = new DArray(this);
        return myArray;
    }
    private DArray myArray;

    bool isSame(DType d)
    {
        return d is this;
    }

    static DInteger
        Bool,
        Byte, UByte, Short, UShort,
        Int, UInt, Long, ULong,
        Char, WChar, DChar;

    static DReal Float, Double, Real;

    // Ignore - we dont support complex numbers yet
    static DReal CFloat, CDouble, CReal;

    static DType Void;

    static this()
    {
        Void   = new DType("void");

        Bool   = new DInteger("bool",    1, true);
        Byte   = new DInteger("byte",    8, false);
        UByte  = new DInteger("ubyte",   8, true);
        Short  = new DInteger("short",  16, false);
        UShort = new DInteger("ushort", 16, true);
        Int    = new DInteger("int",    32, false);
        UInt   = new DInteger("uint",   32, true);
        Long   = new DInteger("long",   64, false);
        ULong  = new DInteger("ulong",  64, true);

        Float  = new DReal("float",  32);
        Double = new DReal("double", 64);
        Real   = new DReal("real",   80);

        Char   = new DInteger("char",    8, true);
        WChar  = new DInteger("wchar",  16, true);
        DChar  = new DInteger("dchar",  32, true);
    }
}

/**
  Class to represent the built-in numerical types, from byte to long, reals and
  complex numbers.

  Should not actually use this, but DInteger, DReal or DComplex.
 */
class DArithmetic : DType
{
    private static char[][DArithmetic] mangle_types;

    static this()
    {
        mangle_types = 
        [
            cast(DArithmetic)
            Bool    : "b",
            Byte    : "g",
            UByte   : "h",
            Short   : "s",
            UShort  : "t",
            Int     : "i",
            UInt    : "k",
            Long    : "l",
            ULong   : "m",

            Float   : "f",
            Double  : "d",
            Real    : "e",

            /*
            CFloat  : "q",
            CDouble : "r",
            CReal   : "c",
            */

            Char    : "a",
            WChar   : "u",
            DChar   : "w"
        ];
    }

    this(char[] name, int bits, bool unsigned)
    {
        super(name, null);
        this.bits = bits;
        this.unsigned = unsigned;
    }

    override int byteSize() { return bits / 8; }

    bool isArithmetic() { return true; }

    override Operation getOperationWith(Operator op, DType that)
    {
        Operation operation;
        if (this is that)
            operation = Operation.builtin(op, unsigned, isReal());
        return operation;
    }

    override char[] mangle()
    {
        return mangle_types[this];
    }

    int bits;
    bool unsigned;
}

class DInteger : DArithmetic
{
    this(char[] name, int bits, bool unsigned)
    {
        super(name, bits, unsigned);
    }

    override bool hasImplicitConversionTo(DType that)
    {
        if (that.isInteger() || that.isReal())
            return true;
        return false;
    }

    override bool isInteger() { return true; }
    override DInteger asInteger() { return this; }
}

class DReal : DArithmetic
{
    this(char[] name, int bits)
    {
        super(name, bits, false);
    }

    override bool hasImplicitConversionTo(DType that)
    {
        if (that.isInteger() || that.isReal())
            return true;
        return false;
    }

    override bool isReal() { return true; }
    override DReal asReal() { return this; }
}

class DStruct : DType
{
    this(Identifier id, DType actual = null)
    {
        super(id, actual);
    }

    int byteSize() { return bytes_total; }

    override bool isStruct() { return true; }
    override DStruct asStruct() { return this; }

    void addMember(DType type, char[] name)
    {
        auto s = DStructMember(type, members.length);
        members[name] = s;

        bytes_total += type.byteSize();
    }

    int indexOf(char[] name)
    {
        if(name in members)
            return members[name].index;

        return -1;
    }

    DType typeOf(char[] name)
    {
        if (auto res = name in members)
            return res.type;
        return null;
    }

    DStructMember[char[]] members;
    private int bytes_total;

    override char[] mangle()
    {
        return "S"~Integer.toString(name.length)~name;
    }

    override bool isSame(DType d)
    {
        if (d is this)
            return true;

        if (!d.isStruct)
            return false;

        auto s = d.asStruct;

        return id == s.id;
    }

    struct DStructMember
    {
        DType type;
        int index;

        char[] toString()
        {
            return type.toString();
        }
    }
}

class DClass : DType
{
    this(Identifier id, DType actual = null)
    {
        super(id, actual);
    }

    int byteSize() { return bytes_total; }

    override bool isClass() { return true; }
    override DClass asClass() { return this; }

    void addMember(DType type, char[] name)
    {
        auto s = DClassMember(type, members.length);
        members[name] = s;

        bytes_total += type.byteSize();
    }

    int indexOf(char[] name)
    {
        if(name in members)
            return members[name].index;

        return -1;
    }

    DType typeOf(char[] name)
    {
        if (auto res = name in members)
            return res.type;
        return null;
    }

    DClassMember[char[]] members;
    private int bytes_total;

    override char[] mangle()
    {
        return "S"~Integer.toString(name.length)~name;
    }

    override bool isSame(DType d)
    {
        if (d is this)
            return true;

        if (!d.isClass)
            return false;

        auto c = d.asClass;

        return id == c.id;
    }

    struct DClassMember
    {
        DType type;
        int index;

        char[] toString()
        {
            return type.toString();
        }
    }
}

class DInterface : DType
{
    this(Identifier id, DType actual = null)
    {
        super(id, actual);
    }

    int byteSize() { return bytes_total; }

    override bool isInterface() { return true; }
    override DInterface asInterface() { return this; }

    void addMember(DType type, char[] name)
    {
        auto s = DInterfaceMember(type, members.length);
        members[name] = s;

        bytes_total += type.byteSize();
    }

    int indexOf(char[] name)
    {
        if(name in members)
            return members[name].index;

        return -1;
    }

    DType typeOf(char[] name)
    {
        if (auto res = name in members)
            return res.type;
        return null;
    }

    override bool isSame(DType d)
    {
        if (d is this)
            return true;

        if (!d.isInterface)
            return false;

        auto i = d.asInterface;

        return id == i.id;
    }

    DInterfaceMember[char[]] members;
    private int bytes_total;

    override char[] mangle()
    {
        return "S"~Integer.toString(name.length)~name;
    }

    struct DInterfaceMember
    {
        DType type;
        int index;

        char[] toString()
        {
            return type.toString();
        }
    }
}

class DStaticArray : DType
{
    this(DType arrayOf, int size, DType actual = null)
    {
        super(arrayOf.id ~ "[" ~ Integer.toString(size) ~ "]", actual);
        this.arrayOf = arrayOf;
        this.size = size;
    }

    override bool isStaticArray() { return true; }
    override DStaticArray asStaticArray() { return this; }

    int byteSize() { return arrayOf.byteSize * size; }

    override bool isSame(DType d)
    {
        if (d is this)
            return true;

        if (!d.isArray)
            return false;

        auto a = d.asStaticArray;

        if (size != a.size)
            return false;

        return arrayOf.isSame(a.arrayOf);
    }

    char[] toString()
    {
        return arrayOf.toString~"["~Integer.toString(size)~"]";
    }


    override char[] mangle()
    {
        return "G"~Integer.toString(size)~arrayOf.mangle;
    }

    DType arrayOf;
    const int size;
}

class DArray : DType
{
    this(DType arrayOf, DType actual = null)
    {
        super(id, actual);
        this.arrayOf = arrayOf;
    }

    override bool isArray() { return true; }
    override DArray asArray() { return this; }

    int byteSize() { return 8; } // FIXME: Size is a pointer + on size. (platform depend)

    override bool isSame(DType d)
    {
        if (d is this)
            return true;

        if (!d.isArray)
            return false;

        auto a = d.asArray;

        return arrayOf.isSame(a.arrayOf);
    }

    override char[] mangle()
    {
        return "G"~arrayOf.mangle; // FIXME: Need correct mangling
    }

    DType arrayOf;
}

class DPointer : DType
{
    this(DType pointerOf, DType actual = null)
    {
        super(id, actual);
        this.pointerOf = pointerOf;
    }

    override bool isPointer() { return true; }
    override DPointer asPointer() { return this; }

    int byteSize() { return DType.Int.byteSize; }

    override bool isSame(DType d)
    {
        if (d is this)
            return true;

        if (!d.isPointer)
            return false;

        auto p = d.asPointer;

        return pointerOf.isSame(p.pointerOf);
    }

    char[] toString()
    {
        if (!pointerOf.isFunction)
            return pointerOf.toString~"*";

        auto f = pointerOf.asFunction;

        char[] res = f.returnType.toString~" function(";

        foreach (i, p ; f.params)
            res ~= i ? ", "~p.toString : p.toString;

        return res ~ ")";
    }

    override char[] mangle()
    {
        return "P"~pointerOf.mangle;
    }

    DType pointerOf;
}

class DFunction : DType
{
    this(Identifier id, DType actual = null)
    {
        super(id, actual);
    }

    override bool isFunction() { return true; }
    override DFunction asFunction() { return this; }

    override bool hasImplicitConversionTo(DType that)
    {
        return returnType.hasImplicitConversionTo(that);
    }

    override char[] mangle()
    {
        char[] res;

        res ~= "F";

        foreach(param ; params)
            res ~= param.mangle;

        res ~= "Z";
        res ~= returnType.mangle;

        return res;
    }

    char[] toString()
    {
        char[] res = returnType.toString~" (";

        foreach (i, p ; params)
            res ~= i ? ", "~p.toString : p.toString;

        return res ~ ")";
    }

    override bool isSame(DType f)
    {
        if (f is this)
            return true;

        if (!f.isFunction)
            return false;

        auto func = f.asFunction;

        if (returnType != func.returnType)
            return false;

        if (params.length != func.params.length)
            return false;

        foreach (i, p ; params)
            if (!p.isSame(func.params[0]))
                return false;

        return true;
    }

    DType[] params;
    DType returnType;
    bool firstParamIsReturnValue = false;
}