view ast/Exp.d @ 68:381975d76baf new_gen

A LOT of bug fixing - also implemented implicit casts. If you do a --ast-dump-code on a target with some algebra of differant types, you should now see the type casts being made. Also, Tests are again back with only switches failing...
author Anders Johnsen <skabet@gmail.com>
date Thu, 01 May 2008 19:25:49 +0200
parents 3fdf20b08a81
children 628cb46ab13b
line wrap: on
line source

module ast.Exp;

import tango.text.Util;
import tango.io.Stdout;

import ast.Decl,
       ast.Stmt;

import lexer.Token;

import sema.SymbolTable,
       sema.DType;

enum ExpType
{
    Binary,
    Negate,
    IntegerLit,
    MemberReference,
    ArrayLookup,
    Identifier,
    AssignExp,
    CallExp,
    CastExp,
}

class Exp
{
    this(ExpType expType) 
    {
        this.expType = expType;
    }

    DType type() { return null; }

    ExpType expType;
    Scope env;
    int stmtIndex;

    Exp simplify()
    {
        return this;
    }
}

class CallExp : Exp
{
    this(Exp exp, Exp[] args)
    {
        super(ExpType.CallExp);
        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;
    }

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


    Exp simplify()
    {
        if(auto t = cast(DStruct)type)
        {
            DFunction func_t = cast(DFunction)exp.type();
            assert(func_t !is null, "Calling on something that isn't a function");
            if (cast(DStruct)func_t.returnType is null)
                return this;

            auto call = cast(Identifier)exp;
            FuncDecl f = env.parentFunction;
            auto i = new Identifier("temp.var");
            i.env = f.env;
            f.env.add(i);
            f.env.find(i).type = t;
            auto ty = new Identifier(t.name);
            auto var = new VarDecl(ty, i, null);
            Exp[] args; 
            args ~= i;
            args ~= this.args;
            auto callExp = new CallExp(exp, args);
            callExp.env = f.env;
            var.env = f.env;
            auto stmtVar = new DeclStmt(var);
            auto stmtCall = new ExpStmt(callExp);
            Stmt[] stmts;
            foreach( index, s ; f.statements)
            {
                if(stmtIndex == index)
                {
                    stmts ~= stmtVar;
                    stmts ~= stmtCall;
                }
                stmts ~= s;
            }
            f.statements = stmts;
            callExp.sret = true;

            return i;
        }
        return this;
    }
}

class AssignExp : Exp
{
    this(Exp identifier, Exp exp)
    {
        super(ExpType.AssignExp);
        this.identifier = identifier;
        this.exp = exp;
    }
    Exp simplify()
    {
        identifier = identifier.simplify;
        exp = exp.simplify;

        return this;
    }

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

    Exp identifier;
    Exp exp;
}

class BinaryExp : Exp
{
    public enum Operator
    {
        Assign,

        Eq, Ne,

        Lt, Le,
        Gt, Ge,

        Add, Sub,
        Mul, Div, Mod,
    }

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

    this(Operator op, Exp left, Exp right)
    {
        super(ExpType.Binary);
        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;
    }

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

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

class NegateExp : Exp
{
    this(Exp exp)
    {
        super(ExpType.Negate);
        this.exp = exp;
    }
    Exp simplify()
    {
        exp = exp.simplify;
        return this;
    }

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

    public Exp exp;
}

class IntegerLit : Exp
{
    this(Token t)
    {
        super(ExpType.IntegerLit);
        this.token = t;
        this.name = substitute(t.get,"_","");
    }

    char[] get()
    {
        return name;
    }
    Exp simplify()
    {
        return this;
    }

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

    

    Token token;
    char[] name;
}

class MemberReference : Exp
{
    this(Exp target, Identifier child)
    {
        super(ExpType.MemberReference);
        this.target = target;
        this.child = child;
    }
    Exp 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.token.get))
            myType = t;
        // no error reporting here
        else assert(0, "Referencing non-existant member");

        return myType;
    }

    Identifier child;
    Exp target;
    private DType myType;
}

class ArrayLookup : Exp
{
    this(Exp target, IntegerLit pos)
    {
        super(ExpType.ArrayLookup);
        this.target = target;
        this.pos = pos;
    }

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

    Exp simplify()
    {
        target = target.simplify;
        pos.simplify;
        return this;
    }

    Exp target;
    IntegerLit pos;
}

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

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

    Exp simplify()
    {
        castType.simplify;
        exp.simplify;
        return this;
    }

    Identifier castType;
    Exp exp;
}

class Identifier : Exp
{
    this(Token t)
    {
        super(ExpType.Identifier);
        this.token = t;
        name = t.get;
    }

    override DType type()
    {
        if (myType !is null)
            return myType;
        myType = env.find(this).type;
        return myType;
    }

    this(char[] name)
    {
        super(ExpType.Identifier);
        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;
    }

    Exp simplify()
    {
        return this;
    }

    Token token;
    char[] name;
    private DType myType;
}