view ast/Exp.d @ 88:eb5b2c719a39 new_gen

Major change to locations, tokens and expressions. A location (now SourceLocation or SLoc) is only 32 bit in size - disadvantage is that it can't find its own text. You have to go through the new SourceManager to do that. This has caused changes to a lot of stuff and removal of DataSource and the old Location Additionally Exp has gotten some location stuff, so we can give proper error messages. Not in Decl and Stmt yet, but thats coming too.
author Anders Halager <halager@gmail.com>
date Sun, 04 May 2008 18:13:46 +0200
parents 29f486ccc203
children 771ac63898e2
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,
    Deref,
    IntegerLit,
    MemberReference,
    Index,
    Identifier,
    ArrayIdentifier,
    PointerIdentifier,
    AssignExp,
    CallExp,
    CastExp,
}

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

    /// Get the type of the expression
    DType type() { return null; }

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

    /// The environment of the expression
    Scope env;

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

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

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

    Exp simplify()
    {
        if(auto t = type.asStruct)
        {
            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(SLoc op, Exp identifier, Exp exp)
    {
        super(ExpType.AssignExp, op);
        this.identifier = identifier;
        this.exp = exp;
    }

    Exp 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,

        Eq, Ne,

        Lt, Le,
        Gt, Ge,

        Add, Sub,
        Mul, Div, Mod,
    }

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

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

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

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

    Exp 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 = substitute(t, "_", "");
    }

    char[] get()
    {
        return name;
    }

    Exp simplify()
    {
        return this;
    }

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

    override SourceRange sourceRange()
    {
        return range;
    }

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

    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.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.isArray())
            return type.asArray().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);
    }

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

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

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

    Identifier castType;
    Exp exp;
}

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 ArrayIdentifier : Identifier
{
    this(Identifier arrayOf, IntegerLit size)
    {
        super(ExpType.ArrayIdentifier, arrayOf.loc);
        this.arrayOf = arrayOf;
        this.size = Integer.parse(size.get);
        this.name = arrayOf.name;
    }

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

    Identifier arrayOf;
    int size;

    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 DType type()
    {
        if (myType !is null)
            return myType;
        myType = env.find(this).type;
        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;
    }

    Exp simplify()
    {
        return this;
    }

    char[] name;
    private DType myType;
}