view ast/Stmt.d @ 44:495188f9078e new_gen

Big update - Moving towards a better, more seperated parser The parser no loner creates the AST directly, but through callbacks(actions). This means the parser can be run with a different set of actions that do something else. The parser is not back to full strength yet, the main thing missing is the various statements and structs. Also added a SmallArray that uses the stack only until a given size is exceeded, after which the array is copied unto the heap.
author Anders Halager <halager@gmail.com>
date Wed, 23 Apr 2008 00:57:45 +0200
parents ce17bea8e9bd
children 9bc660cbdbec
line wrap: on
line source

module ast.Stmt;

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

import ast.Exp,
       ast.Decl;

import sema.SymbolTable,
       misc.Error;

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

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

    StmtType stmtType;
    Scope env;
}

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

    Stmt[] statements;
}

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

    public Exp exp;
}

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

    public Decl decl;
}

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

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

    Exp cond;
    Stmt[] then_body;
    Stmt[] else_body;
}

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

    Exp cond;
    Stmt[] stmts;
}

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

    void addCase(IntegerLit[] values, Stmt[] stmts)
    {
        long[] new_values;
        foreach (lit; values)
            new_values ~= Integer.parse(lit.token.get);
        cases ~= Case(values, stmts, new_values);

        // Make sure there is no two cases with the same value
        // Does it belong here?
        new_values = new_values.dup;
        Array.sort(new_values);
        long[] all_values = Array.unionOf(old_values, new_values);
        if (all_values.length != old_values.length + new_values.length)
        {
            // overlap!
            auto e = new Error(
                    "Can't have multiple cases with the same value."
                    " Values appearing in multiple cases: %0");
            e.loc(values[0].token.location);

            all_values = Array.intersectionOf(old_values, new_values);
            char[][] vals;
            foreach (val; all_values)
                vals ~= Integer.toString(val);
            e.arg(vals);
            /*
            foreach (c; cases)
                foreach (i, v; c.values_converted)
                    if (Array.bsearch(all_values, v))
                        e.tok(c.values[i].token);
            */
            throw e;
        }
        old_values = all_values;
    }

    void setDefault(Stmt[] stmts)
    {
        if (defaultBlock.length != 0)
            throw new Error("Switch statements can't have multiple defaults");
        defaultBlock = stmts;
        if (cases.length > 0)
            cases[$ - 1].followedByDefault = true;
    }

    Exp cond;
    Case[] cases;
    Stmt[] defaultBlock;

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

    private long[] old_values;
}