view ast/Exp.d @ 139:a22e3663de89

Fixed up our simplify functions Removed some unused stuff and changed all function calls to have () attached. We should only omit parens when calling something that is supposed to be a property - not a function like simplify
author Anders Halager <halager@gmail.com>
date Fri, 18 Jul 2008 13:32:34 +0200
parents 2be29b296081
children a14ac9e5c858
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,
}

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.findMember(child.get);
        return null;
    }

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

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

        DStruct st = cast(DStruct)target.type;
        assert(st, "Only structs have members");
        if (auto t = st.typeOf(child.name))
            myType = t;
        // no error reporting here
        else assert(0, "Referencing non-existant member");

        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);
    }

    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 null; }

    char[] str;
}

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))
            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;
}