view sema/SymbolTableBuilder.d @ 53:da551f90e03f new_gen

Added struct decl and forward ref. A note on structs: they need to make a new scope when declared. Otherwise you could access struct members as globals
author Anders Johnsen <skabet@gmail.com>
date Sat, 26 Apr 2008 18:52:27 +0200
parents 9bc660cbdbec
children 79cb0afafabe
line wrap: on
line source

module sema.SymbolTableBuilder;

import tango.io.Stdout,
       tango.core.Array : find;

public
import sema.SymbolTable;

import sema.Visitor;

class SymbolTableBuilder : Visitor!(void)
{
    override void visit(Decl[] decls)
    {
        auto sb = new ScopeBuilder();
        sb.visit(decls);
        foreach (decl; decls)
            visitDecl(decl);
    }

    override void visitFuncDecl(FuncDecl d)
    {
        d.env.find(d.identifier).type = typeOf(d.type, d.env);
        visitExp(d.type);
        visitExp(d.identifier);
        foreach (arg; d.funcArgs)
            visitDecl(arg);
        foreach (stmt; d.statements)
            visitStmt(stmt);
    }

    override void visitVarDecl(VarDecl d)
    {
        if (d.init)
            visitExp(d.init);

        d.env.find(d.identifier).type = typeOf(d.type, d.env);
        visitExp(d.type);
        visitExp(d.identifier);
    }

    override void visitStructDecl(StructDecl s)
    {
        DType[char[]] types;
        foreach(varDecl ; s.vars)
        {
            types[varDecl.identifier.get] = typeOf(varDecl.type, s.env);
        }

        (cast(DStruct)s.env.types[s.identifier.get]).setMembers(types);
        super.visitStructDecl(s);
    }

    DType typeOf(Identifier id, Scope sc)
    {
        return sc.findType(id);

        /*
        if (auto type = id.get in types)
            return *type;
        DType res = new DType(id);
        types[id.get] = res;
        return res;*/
    }
}

class ScopeBuilder : Visitor!(void)
{
    this()
    {
        table ~= new Scope;
        table[0].types["void"]    = DType.Void;
        table[0].types["bool"]    = DType.Bool;
        table[0].types["byte"]    = DType.Byte;
        table[0].types["ubyte"]   = DType.UByte;
        table[0].types["short"]   = DType.Short;
        table[0].types["ushort"]  = DType.UShort;
        table[0].types["int"]     = DType.Int;
        table[0].types["uint"]    = DType.UInt;
        table[0].types["long"]    = DType.Long;
        table[0].types["ulong"]   = DType.ULong;
    }

    override void visit(Decl[] decls)
    {
        foreach (decl; decls)
            visitDecl(decl);
    }

    override void visitDecl(Decl d)
    {
        d.env = current();
        super.visitDecl(d);
    }

    override void visitStmt(Stmt s)
    {
        s.env = current();
        super.visitStmt(s);
    }

    override void visitExp(Exp e)
    {
        e.env = current();
        super.visitExp(e);
    }

    override void visitFuncDecl(FuncDecl d)
    {
        auto sym = current().add(d.identifier);
        auto sc = push();

        visitExp(d.type);
        visitExp(d.identifier);
        d.env = current();
        sc.parentFunction = sym;
        foreach (arg; d.funcArgs)
            visitDecl(arg);
        foreach (stmt; d.statements)
            visitStmt(stmt);
        pop(sc);
    }

    override void visitVarDecl(VarDecl d)
    {
        if (d.init)
            visitExp(d.init);

        if (need_push > 0 && current().parentFunction !is null) {
            push();
            --need_push;
        }

        auto sc = current();
        auto sym = sc.add(d.identifier);
        d.env = sc;
        visitExp(d.type);
        visitExp(d.identifier);
    }

    override void visitStructDecl(StructDecl s)
    {
        auto sc = current();
        auto sym = sc.add(s.identifier);

        auto type = new DStruct(s.identifier);
        
        sc.types[s.identifier.get] = type;
        s.env = sc;
        super.visitStructDecl(s);
    }

    override void visitDeclStmt(DeclStmt d)
    {
        ++need_push;
        super.visitDeclStmt(d);
    }
    private uint need_push = 0;

    override void visitIfStmt(IfStmt s)
    {
        s.env = current();
        visitExp(s.cond);
        auto sc = push();
        visitStmt(s.then_body);
        pop(sc);

        if (s.else_body !is null)
        {
            sc = push();
            visitStmt(s.else_body);
            pop(sc);
        }
    }

    override void visitWhileStmt(WhileStmt s)
    {
        s.env = current();
        auto sc = push();
        super.visitWhileStmt(s);
        pop(sc);
    }

    override void visitCompoundStmt(CompoundStatement s)
    {
        s.env = current();
        auto sc = push();
        super.visitCompoundStmt(s);
        pop(sc);
    }

private:
    Scope[] table;

    Scope push()
    {
        auto sc = new Scope(current());
        table ~= sc;
        return sc;
    }

    Scope pop(Scope sc = null)
    {
        if (sc !is null)
        {
            table.length = table.find(sc);
            return sc;
        }

        auto res = table[$ - 1];
        table.length = table.length - 1;
        return res;
    }

    Scope current()
    {
        return table[$ - 1];
    }
}