view ast/Exp.d @ 192:fda35d57847e

Fixed String parsing, so that they get created with the right type in AST. Also added so that you can parse options to the test program, that will mirror them to Dang. Eg. ./tests/run --semantic-only will pass --semantic-only to Dang on each run.
author Anders Johnsen <skabet@gmail.com>
date Fri, 25 Jul 2008 15:00:54 +0200
parents 7b274cfdc1dc
children 658178183018
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,
    AddressOfExp,
    IntegerLit,
    MemberReference,
    Index,
    Identifier,
    AssignExp,
    CallExp,
    CastExp,
    StringExp,
    NewExp,

    IdentifierTypeExp,
    ArrayTypeExp,
    StaticArrayTypeExp,
    PointerTypeExp,
    FunctionTypeExp,
    ArrayLiteralExp,
}

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 = exp.type.asCallable();
        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;
    Symbol callSym;
    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() 
    {
        if (_type)
            return _type;
        return exp.type().asPointer().pointerOf; 
    }

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

    DType _type;
    public Exp exp;
}

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

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

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

    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 )
        {
            Symbol st = target.getSymbol;
            if (auto t = st.findMembers(child.name))
                myType = t[0].type;
//            else assert(0, "Referencing non-existant member");
        }
        else if ( target.type.isClass )
        {
            Symbol cl = target.getSymbol;
            if (auto t = cl.findMembers(child.name))
                myType = t[0].type;
//            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() 
    {
        switch (data.type)
        {
            case StringType.Char:
                return DType.Char.getAsStaticArray(data.data.length); 
            case StringType.WChar:
                return DType.WChar.getAsStaticArray(data.data.length/2); 
            case StringType.DChar:
                return DType.DChar.getAsStaticArray(data.data.length/4); 
        }
    }

    char[] str;
    String 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 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))
            if(decl.length)
                return decl[$-1].sym;
        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;
    }

    override SourceRange sourceRange()
    {
        return SourceRange(loc, loc + name.length);
    }

    char[] name;
    private DType myType;
}

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

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

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

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

    Identifier pointerOf;
}

class StaticArrayTypeExp : IdentifierTypeExp
{
    this(IdentifierTypeExp arrayOf, IntegerLit size)
    {
        super(ExpType.StaticArrayTypeExp, 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 ArrayTypeExp : IdentifierTypeExp
{
    this(IdentifierTypeExp arrayOf)
    {
        super(ExpType.ArrayTypeExp, arrayOf.loc);
        this.arrayOf = arrayOf;
        this.name = arrayOf.name;
    }

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

    Identifier arrayOf;

    private DType myType;
}

class FunctionTypeExp : IdentifierTypeExp
{
    this(IdentifierTypeExp returnType, VarDecl[] decls)
    {
        super(ExpType.FunctionTypeExp, returnType.loc);
        this.returnType = returnType;
        this.decls = decls;
    }

    override DType type()
    {
        if (myType)
            return myType;
        auto t  = new DFunction(returnType);
        t.returnType = returnType.type;
        foreach (decl ; decls)
            t.params ~= decl.identifier.type;

        myType = t.getPointerTo;
        return myType;
    }

    VarDecl[] decls;
    IdentifierTypeExp returnType;
    private DType myType;
}

class ArrayLiteralExp : Exp
{
    this(Exp[] exps, SLoc begin, SLoc end)
    {
        super(ExpType.ArrayLiteralExp, begin);
        this.exps = exps;
        this.begin = begin;
        this.end = end;
    }

    override DType type()
    {
        return exps[0].type.getAsStaticArray(exps.length);
    }

    Exp[] exps;
    SLoc begin, end;
}