view ast/Stmt.d @ 183:8ea749b7da91

Fixed a few errors so that two more tests passes. Also, now you only need a type in a function param.
author Anders Johnsen <skabet@gmail.com>
date Fri, 25 Jul 2008 10:59:16 +0200
parents ee202c72cd30
children
line wrap: on
line source

module ast.Stmt;

import Array = tango.core.Array,
       Integer = tango.text.convert.Integer,
       tango.io.Stdout;

import ast.Exp,
       ast.Decl;

import sema.Scope,
       sema.VC,
       basic.Message,
       basic.SourceLocation;

enum StmtType
{
    Stmt,
    Compound,
    Decl,
    Exp,
    Return,
    If,
    While,
    For,
    Switch,
}

abstract class Stmt
{
    this(StmtType stmtType = StmtType.Stmt)
    {
        this.stmtType = stmtType;
    }

    void simplify()
    {
    }

    void verify(VC vc) {}

    /// The "main" location of the expression.
    SourceLocation loc;

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

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

    StmtType stmtType;
    Scope env;
    int stmtIndex;
}

class CompoundStatement : Stmt
{
    this(Stmt[] stmts)
    {
        super(StmtType.Compound);
        this.statements = stmts;
    }

    override void simplify()
    {
        foreach (stmt; statements )
            stmt.simplify();
    }

    Stmt[] statements;
}

class ReturnStmt : Stmt
{
    this()
    {
        super(StmtType.Return);
    }

    // Needed?
    override void simplify()
    {
        FuncDecl f = env.parentFunction;
        if (exp)
           exp = exp.simplify();
        if (f !is null && f.sret)
        {
            auto i = new Identifier("ret.val");
            i.env = f.env;
            auto ass = new AssignExp(SLoc.Invalid, BinaryExp.Operator.Assign, i, exp);
            ass.env = f.env;
            auto assStmt = new ExpStmt(ass);
            assStmt.env = f.env;

            Stmt[] stmts;
            foreach(index, stmt ; f.statements)
            {
                if(stmtIndex == index)
                    stmts ~= assStmt;

                stmts ~= stmt;
            }
            f.statements = stmts;
            exp = null;
        }
    }

    public Exp exp;
}

class DeclStmt : Stmt
{
    this(Decl decl)
    {
        super(StmtType.Decl);
        this.decl = decl;
    }

    override void simplify()
    {
        decl.simplify();
    }

    public Decl decl;
}

class ExpStmt : Stmt
{
    this(Exp exp)
    {
        super(StmtType.Exp);
        this.exp = exp;
    }

    override void simplify()
    {
        exp = exp.simplify();
    }

    public Exp exp;
}

class IfStmt : Stmt
{
    this(Exp cond, Stmt then, Stmt el = null)
    {
        super(StmtType.If);
        this.cond = cond;
        this.then_body = then;
        this.else_body = el;
    }

    override void simplify()
    {
        cond = cond.simplify();
        then_body.simplify();
        if (else_body)
            else_body.simplify();
    }

    Exp cond;
    Stmt then_body;
    Stmt else_body;
}

class WhileStmt : Stmt
{
    this(Exp cond, Stmt stmts)
    {
        super(StmtType.While);
        this.cond = cond;
        this.whileBody = stmts;
    }

    override void simplify()
    {
        cond = cond.simplify();
        whileBody.simplify();
    }

    Exp cond;
    Stmt whileBody;
}

class ForStmt : Stmt
{
    this(Stmt init, Exp cond, Exp incre, Stmt stmts)
    {
        super(StmtType.For);
        this.init = init;
        this.cond = cond;
        this.incre = incre;
        this.forBody = stmts;
    }

    override void simplify()
    {
        if (cond)
            cond = cond.simplify();
        forBody.simplify();
    }

    Exp cond, incre;
    Stmt init, forBody;
}

class SwitchStmt : Stmt
{
    this(SourceLocation loc, Exp target)
    {
        super(StmtType.Switch);
        cond = target;
        this.loc = loc;
    }

    void addCase(SourceLocation _case, Exp[] values, Stmt[] stmts)
    {
        cases ~= Case(_case, values, stmts);
    }

    void setDefault(SourceLocation _default, Stmt[] stmts)
    {
        if (defaultBlock !is null)
            extraDefaultBlocks = true;

        defaultBlock = stmts;
        defaultLoc = _default;
        if (cases.length > 0)
            cases[$ - 1].followedByDefault = true;
    }

    override void simplify()
    {
        cond = cond.simplify();
        foreach ( stmt ; defaultBlock )
            stmt.simplify();
        foreach ( c ; cases )
            foreach ( stmt ; c.stmts )
                stmt.simplify();
    }

    override void verify(VC vc)
    {
        if (extraDefaultBlocks)
            vc.msg.report(MultipleDefaults, defaultLoc);

        if (cases.length == 0)
            return;

        scope long[] all_values;
        foreach (ref Case; cases)
        {
            long[] new_values;
            foreach (exp; Case.values)
                if (auto lit = cast(IntegerLit)exp)
                    new_values ~= Integer.parse(lit.get);
                else
                    // We flag all non-literals and ignore them
                    vc.msg.report(InvalidCaseValue, exp.loc);
            Case.values_converted = new_values;
            all_values ~= new_values;
        }

        Array.sort(all_values);
        char[][] overlapping;
        size_t i = 0;
        while ((i = Array.findAdj(all_values)) < all_values.length
                && all_values.length > 0)
        {
            overlapping ~= Integer.toString(all_values[i]);
            auto similar = Array.count(all_values, all_values[i]);
            all_values = all_values[i + similar .. $];
        }
        if (overlapping.length > 0)
            vc.msg.report(OverlappingCases, loc).arg(overlapping);
    }

    Exp cond;
    Case[] cases;
    Stmt[] defaultBlock;
    private bool extraDefaultBlocks = false;
    private SourceLocation defaultLoc;

    struct Case
    {
        SourceLocation caseLoc;
        Exp[] values;
        Stmt[] stmts;
        long[] values_converted;
        bool followedByDefault = false;
    }
}