view sema/ScopeCheck.d @ 158:57b0b4464a0b

Parsing "new", putting it in AST and performs some tests on it. Eg. if the contructor exists and the params matches.
author Anders Johnsen <skabet@gmail.com>
date Tue, 22 Jul 2008 00:33:58 +0200
parents a14ac9e5c858
children 7982eb63c0eb
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).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)
    {
        switch(m.target.expType)
        {
            case ExpType.Identifier:
                auto target = cast(Identifier)m.target;
                auto child = m.child;
                auto st = target.getSymbol;
                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;
            case ExpType.MemberReference:
                Symbol s = internalVisitMemberRef(cast(MemberReference)m.target);
                if(!s)
                    return null;
                auto target = cast(Identifier)m.target;
                auto child = m.child;
                auto res = s.findMembers(child.get);

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

                return res.length ? res[0] : null;
        }
    }

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