view ast/Exp.d @ 164:ba94fd563548

The symbol for the constructor a "new"-exp is calling is now stored in callSym in NewExp.
author Anders Johnsen <skabet@gmail.com>
date Tue, 22 Jul 2008 16:53:47 +0200
parents 0f38f1a0f06f
children 7982eb63c0eb
line wrap: on
line source

module ast.Exp;

import tango.text.Util,
       Integer = tango.text.convert.Integer;
import tango.io.Stdout;

import ast.Decl,
       ast.Stmt;

import lexer.Token;

import sema.Scope,
       sema.Symbol,
       sema.DType;

import basic.LiteralParsing;

enum ExpType
{
    Binary,
    Negate,
    Deref,
    IntegerLit,
    MemberReference,
    Index,
    Identifier,
    ArrayIdentifier,
    StaticArrayIdentifier,
    PointerIdentifier,
    AssignExp,
    CallExp,
    CastExp,
    StringExp,
    NewExp,
}

abstract class Exp
{
    this(ExpType expType, SLoc loc)
    {
        this.expType = expType;
        this.loc = loc;
    }

    /**
      Get the fully qualified name for the expression (if it can be resolved to
      one) - otherwise null is returned
     **/
    char[] getFQN() { return null; }

    /// The same as getFQN, except that the name is mangled
    char[] getMangledFQN() { return null; }

    /**
      Try to get the symbol the expression represents.

      Returns null for most expressions as they don't represent any symbol.
      Identifiers and member references can have a sensible value.
     **/
    Symbol getSymbol() { return null; }

    /// Get the type of the expression
    abstract DType type();

    /// Indicates which type the expression is - to avoid a lot of casts
    ExpType expType;

    /// The environment of the expression
    Scope env;

    Symbol symbol;

    int stmtIndex;

    /**
      The "main" location of the expression.
      What exactly this represents varies but for most things its the start
      while for a binary expression its the operator.
     **/
    SourceLocation loc;

    /// Return the starting location of this expression
    SourceLocation startLoc() { return loc; }

    /// Get the full extents of the expression
    SourceRange sourceRange() { return SourceRange(loc, loc + 1); }

    /// Do some simplifications
    Exp simplify() { return this; }
}

class CallExp : Exp
{
    this(Exp exp, Exp[] args)
    {
        super(ExpType.CallExp, exp.loc);
        this.exp = exp;
        this.args = args;
    }

    override DType type()
    {
        DFunction f = cast(DFunction)exp.type();
        assert(f !is null, "Can only call functions");
        return f.returnType;
    }

    override CallExp simplify()
    {
        foreach (ref arg; args)
            arg = arg.simplify();
        exp = exp.simplify();
        return this;
    }

    Exp exp;
    Exp[] args;
    bool sret = false;

    override SourceRange sourceRange()
    {
        SourceRange res = exp.sourceRange;
        if (args.length > 0)
            res = res + args[$ - 1].sourceRange;
        return res;
    }
}

class AssignExp : BinaryExp
{
    this(SLoc op_loc, Operator op, Exp identifier, Exp exp)
    {
        super(ExpType.AssignExp, op_loc, op, identifier, exp);
        this.identifier = identifier;
        this.exp = exp;
    }

    override AssignExp simplify()
    {
        identifier = identifier.simplify();
        exp = exp.simplify();

        return this;
    }

    override SourceRange sourceRange()
    {
        return identifier.sourceRange + exp.sourceRange;
    }

    override DType type() { return identifier.type(); }

    Exp identifier;
    Exp exp;
}

class BinaryExp : Exp
{
    public enum Operator
    {
        Assign,
        AddAssign,
        SubAssign,
        MulAssign,
        DivAssign,
        ModAssign,

        Eq, Ne,

        Lt, Le,
        Gt, Ge,

        Add, Sub,
        Mul, Div, Mod,

        LeftShift, RightShift, UnsignedRightShift,

        And, Or, Xor,
    }

    char[][] getOp = ["=","+=","-=","*=","/=","%=","==","!=","<","<=",">",">=","+","-","*","/","%","<<",">>",">>>"];

    this(SLoc op_loc, Operator op, Exp left, Exp right)
    {
        super(ExpType.Binary, op_loc);
        this.op = op;
        this.left = left;
        this.right = right;
    }

    protected this(ExpType e, SLoc op_loc, Operator op, Exp left, Exp right)
    {
        super(e, op_loc);
        this.op = op;
        this.left = left;
        this.right = right;
    }

    override DType type()
    {
        if (myType)
            return myType;

        if (op == Operator.Eq || 
            op == Operator.Ne ||
            op == Operator.Lt ||
            op == Operator.Le ||
            op == Operator.Gt ||
            op == Operator.Ge)
        {
            myType = DType.Bool;
            return myType;
        }

        DType l = left.type;
        DType r = right.type;
        if (l is r)
            myType = l;
        else if (l.hasImplicitConversionTo(r))
            myType = r;
        else if (r.hasImplicitConversionTo(l))
            myType = l;
        else
            return null;
        return myType;
    }

    override SLoc startLoc() { return left.startLoc(); }

    override SourceRange sourceRange()
    {
        return left.sourceRange + right.sourceRange;
    }

    char[] resultType()
    {
        if (op >= Operator.Eq && op <= Operator.Ge)
            return "bool";
        return null;
    }

    override BinaryExp simplify()
    {
        left = left.simplify();
        right = right.simplify();
        return this;
    }

    Operator op;
    Exp left, right;
    private DType myType;
}

class NegateExp : Exp
{
    this(SLoc op, Exp exp)
    {
        super(ExpType.Negate, op);
        this.exp = exp;
    }

    override NegateExp simplify()
    {
        exp = exp.simplify();
        return this;
    }

    override DType type() { return exp.type(); }

    override SourceRange sourceRange()
    {
        return SourceRange(loc) + exp.sourceRange;
    }

    public Exp exp;
}

class DerefExp : Exp
{
    this(SLoc op, Exp exp)
    {
        super(ExpType.Deref, op);
        this.exp = exp;
    }

    override DerefExp simplify()
    {
        exp = exp.simplify();
        return this;
    }

    override DType type() 
    {
        return exp.type().asPointer().pointerOf; 
    }

    override SourceRange sourceRange()
    {
        return SourceRange(loc) + exp.sourceRange;
    }

    public Exp exp;
}

class IntegerLit : Exp
{
    this(SLoc loc, char[] t)
    {
        super(ExpType.IntegerLit, loc);
        range = SourceRange(loc, loc + t.length);
        this.name = t;
    }

    char[] get()
    {
        return name;
    }

    override IntegerLit simplify()
    {
        return this;
    }

    override DType type() 
    { 
        switch(number.type)
        {
            case NumberType.Int:
                return DType.Int;
            case NumberType.Long:
                return DType.Long;
            case NumberType.ULong:
                return DType.ULong;
            case NumberType.Double:
                return DType.Double;
            case NumberType.Real:
                return DType.Real;
        }
    }

    override SourceRange sourceRange()
    {
        return range;
    }

    Number number;

    char[] name;
    private SourceRange range;
}

class MemberReference : Exp
{
    this(SLoc dot, Exp target, Identifier child)
    {
        super(ExpType.MemberReference, dot);
        this.target = target;
        this.child = child;
    }

    override char[] getFQN()
    {
        return getSymbol().getFQN();
    }

    override char[] getMangledFQN()
    {
        return target.type.mangle() ~ child.getMangledFQN();
    }

    override Symbol getSymbol()
    {
        auto s = target.getSymbol();
        if (s !is null)
            return s.findMembers(child.get)[0];
        return null;
    }

    override MemberReference simplify()
    {
        target = target.simplify();
        return this;
    }

    override DType type()
    {
        if (myType)
            return myType;

        if ( target.type.isStruct )
        {
            DStruct st = target.type.asStruct;
            if (auto t = st.typeOf(child.name))
                myType = t;
//            else assert(0, "Referencing non-existant member");
        }
        else if ( target.type.isClass )
        {
            DClass cl = target.type.asClass;
            if (auto t = cl.typeOf(child.name))
                myType = t;
//            else assert(0, "Referencing non-existant member");
        }
        else
            assert(0, "Only structs and classes have members");
        // no error reporting here

        return myType;
    }

    override SLoc startLoc() { return target.startLoc(); }

    override SourceRange sourceRange()
    {
        return target.sourceRange + child.sourceRange;
    }

    Identifier child;
    Exp target;
    private DType myType;
}

class IndexExp : Exp
{
    this(Exp target, SLoc left_bracket, Exp index, SLoc right_bracket)
    {
        super(ExpType.Index, target.startLoc);
        this.target = target;
        this.left_bracket = left_bracket;
        this.index = index;
        this.right_bracket = right_bracket;
    }

    override DType type()
    {
        DType type = target.type();
        if (type.isStaticArray())
            return type.asStaticArray().arrayOf;
        else if (type.isPointer())
            return type.asPointer().pointerOf;
        else assert(0, "Can only index pointers and arrays");
    }

    override SourceRange sourceRange()
    {
        return target.sourceRange + SourceRange(right_bracket);
    }

    override IndexExp simplify()
    {
        target = target.simplify();
        index = index.simplify();
        return this;
    }

    Exp target;
    Exp index;
    SLoc left_bracket, right_bracket;
}

class CastExp : Exp
{
    this(SLoc loc, Identifier castType, Exp exp)
    {
        super(ExpType.CastExp, loc);
        this.castType = castType;
        this.exp = exp;
    }

    override DType type()
    {
        return env.findType(this.castType.get);
    }

    override CastExp simplify()
    {
        castType = castType.simplify();
        exp = exp.simplify();
        return this;
    }

    override SourceRange sourceRange()
    {
        return SourceRange(loc) + exp.sourceRange;
    }

    Identifier castType;
    Exp exp;
}

class StringExp : Exp
{
    this(SLoc loc, char[] str)
    {
        super(ExpType.StringExp, loc);
        this.str = str;
    }

    override DType type() { return DType.Char.getAsStaticArray(data.length); }

    char[] str;
    ubyte[] data;
}

class NewExp : Exp
{
    this(Identifier newType, Exp[] a_args, Exp[] c_args)
    {
        super(ExpType.NewExp, newType.loc);
        this.newType = newType;
        this.a_args = a_args;
        this.c_args = c_args;
    }

    override DType type() 
    { 
        return env.findType(this.newType.get); 
    }

    Exp[] a_args, c_args;
    Identifier newType;
    Symbol callSym;
}

class PointerIdentifier : Identifier
{
    this(Identifier pointerOf)
    {
        super(ExpType.PointerIdentifier, pointerOf.loc);
        this.pointerOf = pointerOf;
        this.name = pointerOf.name;
    }

    override DType type()
    {
        return pointerOf.type.getPointerTo();
    }

    Identifier pointerOf;
}

class StaticArrayIdentifier : Identifier
{
    this(Identifier arrayOf, IntegerLit size)
    {
        super(ExpType.StaticArrayIdentifier, arrayOf.loc);
        this.arrayOf = arrayOf;
        this.size = Integer.parse(size.get);
        this.name = arrayOf.name;
    }

    override DType type()
    {
        return arrayOf.type.getAsStaticArray(size);
    }

    Identifier arrayOf;
    int size;

    private DType myType;
}

class ArrayIdentifier : Identifier
{
    this(Identifier arrayOf)
    {
        super(ExpType.ArrayIdentifier, arrayOf.loc);
        this.arrayOf = arrayOf;
        this.name = arrayOf.name;
    }

    override DType type()
    {
        return arrayOf.type.getAsArray();
    }

    Identifier arrayOf;

    private DType myType;
}

class Identifier : Exp
{
    this(SLoc loc, char[] name)
    {
        super(ExpType.Identifier, loc);
        this.name = name;
    }

    protected this(ExpType t, SLoc loc)
    {
        super(t, loc);
    }

    override char[] getFQN()
    {
        return name;
    }

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

    override Symbol getSymbol()
    {
        if (auto decl = env.find(this.get))
            return decl.sym;
        else
            return null;
    }

    override DType type()
    {
        if (myType !is null)
            return myType;
        else if (auto sym = getSymbol)
            myType = sym.type;
        else
            myType = DType.Int;

        return myType;
    }

    this(char[] name)
    {
        super(ExpType.Identifier, SLoc.Invalid);
        this.name = name;
    }

    char[] get()
    {
        return name;
    }

    hash_t toHash()
    {
        return jhash(name);
    }

    int opCmp(Object o)
    {
        if (auto id = cast(Identifier)o)
            return typeid(char[]).compare(&name, &id.name);
        return 0;
    }

    int opEquals(Object o)
    {
        if (auto id = cast(Identifier)o)
            return typeid(char[]).equals(&name, &id.name);
        return 0;
    }

    override Identifier simplify()
    {
        return this;
    }

    void setType(DType myType)
    {
        this.myType = myType;
    }

    char[] name;
    private DType myType;
}