view sema/ScopeCheck.d @ 168:7982eb63c0eb

Some changes to get function overloading to work. Also class inherit works now - to some extend. needs vtables and all the complex stuff of it.
author Anders Johnsen <skabet@gmail.com>
date Thu, 24 Jul 2008 12:06:48 +0200
parents 57b0b4464a0b
children 01c2c49775ef
line wrap: on
line source

module sema.ScopeCheck;

import sema.Visitor,
       sema.Symbol,
       sema.Scope,
       sema.DType;

import basic.Message,
       basic.Attribute;

import tango.io.Stdout;

class ScopeCheck : Visitor!(void)
{

    this(MessageHandler messages)
    {
        this.messages = messages;
    }

    override void visitIdentifier(Identifier i)
    {
        auto symbol = i.env.find(i.get);

        if(symbol is null)
            messages.report(UndefinedIdentifier, i.loc)
                .arg(i.get);
    }

    override void visitVarDecl(VarDecl d)
    {
        if(!d.env.findType(d.varType.get))
            messages.report(UndefinedType, d.varType.loc)
                .arg(d.varType.get);

        auto env = d.env;
        if (d.env.enclosing)
            if (d.env.enclosing.find(d.identifier.get) !is null)
                if (d.env.parentFunction !is null)
                    while( d.env.parentFunction.env !is env)
                    {
                        if (d.env.enclosing.find(d.identifier.get)[0].env == env)
                            messages.report(CannotRedeclare, d.identifier.loc)
                                .arg(d.identifier.get);
                        env = env.enclosing;
                    }

        visitExp(d.identifier);
        if (d.init)
            visitExp(d.init);
    }

    override void visitFuncDecl(FuncDecl f)
    {
        visitExp(f.identifier);

        inFunction = true;
        foreach (stmt; f.statements)
            visitStmt(stmt);
        inFunction = false;
    }

    override void visitImportDecl(ImportDecl) { }

    override void visitCastExp(CastExp exp)
    {
        visitExp(exp.exp);
    }

    override void visitMemberReference(MemberReference m)
    {
        internalVisitMemberRef(m);
    }

    private Symbol internalVisitMemberRef(MemberReference m)
    {
        Symbol visitRef(MemberReference m, Identifier target, Symbol st)
        {
            auto child = m.child;
            auto res = st.findMembers(child.get);

            if(!res.length)
                messages.report(MissingMember, m.loc)
                    .arg(st.type.name)
                    .arg(target.get)
                    .arg(child.get);
            else
                internalCheckProtection(res[0], child);

            return res.length ? res[0] : null;
        }
        switch(m.target.expType)
        {
            case ExpType.Identifier:
                return visitRef(m, cast(Identifier)m.target,
                        (cast(Identifier)m.target).getSymbol);
            case ExpType.MemberReference:
                Symbol s = internalVisitMemberRef(cast(MemberReference)m.target);
                if(!s)
                    return null;
                return visitRef(m, cast(Identifier)m.target, s);
        }
    }

    override void visitExp(Exp exp)
    {
        if (exp.expType == ExpType.Identifier && inFunction
            && exp.env.find((cast(Identifier)exp).get) !is null)
        {
            if (exp.env.findType((cast(Identifier)exp).get) is null)
                internalCheckProtection(
                    exp.env.find((cast(Identifier)exp).get)[0].sym, 
                    cast(Identifier)exp);
        }

        super.visitExp(exp);
    }

    private void internalCheckProtection(Symbol sym, Identifier iden)
    {
        if (isChildOf(sym.decl.env, iden.env))
            return;

        switch(sym.decl.att.getProtection)
        {
            case Protection.Private:
/*                if (iden.env.inModule == sym.decl.getIdentifier.env.inModule
                    && sym.decl.getIdentifier.env.enclosing == iden.env.inModule)
                {}
                else*/
                messages.report(CannotAccessPrivate, iden.loc);
                return;
            default:
                return;
        }
    }

    private bool isChildOf(Scope parent, Scope child)
    {
        if (child is parent)
            return true;

        if (child.enclosing !is null)
            return isChildOf(parent, child.enclosing);

        return false;
    }

    private bool isType(char[] s)
    {
        return (s in types? true : false);
    }

    int[char[]] types;
    MessageHandler messages;
    bool inFunction;
}