// $Id: modifier.cpp,v 1.5 1999/03/09 14:37:17 shields Exp $
copyright notice

#include "config.h"
#include "semantic.h"

AccessFlags Semantic::ProcessClassModifiers(AstClassDeclaration *class_declaration)
{
    AccessFlags access_flags;

    for (int i = 0; i < class_declaration -> NumClassModifiers(); i++)
    {
        AstModifier *modifier = class_declaration -> ClassModifier(i);

        switch(modifier -> kind)
        {
            case Ast::ABSTRACT:
                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_ABSTRACT();

                 if (access_flags.ACC_FINAL())
                 {
                     ReportSemError(SemanticError::FINAL_ABSTRACT_CLASS,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 break;
            case Ast::FINAL:
                 if (access_flags.ACC_FINAL())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_FINAL();

                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::FINAL_ABSTRACT_CLASS,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 break;
            case Ast::PUBLIC:
                 if (access_flags.ACC_PUBLIC())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PUBLIC();
                 break;
            case Ast::STRICTFP:
                 if (access_flags.ACC_STRICTFP())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_STRICTFP();
                 break;
            default:
                 ReportSemError(SemanticError::INVALID_TOP_LEVEL_CLASS_MODIFIER,
                                modifier -> modifier_kind_token,
                                modifier -> modifier_kind_token,
                                lex_stream -> Name(modifier -> modifier_kind_token));
                 break;
        }
    }

    return access_flags;
}



AccessFlags Semantic::ProcessLocalClassModifiers(AstClassDeclaration *class_declaration)
{
    AccessFlags access_flags;

    for (int i = 0; i < class_declaration -> NumClassModifiers(); i++)
    {
        AstModifier *modifier = class_declaration -> ClassModifier(i);

        switch(modifier -> kind)
        {
            case Ast::ABSTRACT:
                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_ABSTRACT();

                 if (access_flags.ACC_FINAL())
                 {
                     ReportSemError(SemanticError::FINAL_ABSTRACT_CLASS,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 break;
            case Ast::FINAL:
                 if (access_flags.ACC_FINAL())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_FINAL();

                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::FINAL_ABSTRACT_CLASS,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 break;
            case Ast::STRICTFP:
                 if (access_flags.ACC_STRICTFP())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_STRICTFP();
                 break;
            default:
                 ReportSemError(SemanticError::INVALID_LOCAL_CLASS_MODIFIER,
                                modifier -> modifier_kind_token,
                                modifier -> modifier_kind_token,
                                lex_stream -> Name(modifier -> modifier_kind_token));
                 break;
        }
    }

    return access_flags;
}


AccessFlags Semantic::ProcessNestedClassModifiers(AstClassDeclaration *class_declaration)
{
    AccessFlags access_flags;

    for (int i = 0; i < class_declaration -> NumClassModifiers(); i++)
    {
        AstModifier *modifier = class_declaration -> ClassModifier(i);

        switch(modifier -> kind)
        {
            case Ast::ABSTRACT:
                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_ABSTRACT();

                 if (access_flags.ACC_FINAL())
                 {
                     ReportSemError(SemanticError::FINAL_ABSTRACT_CLASS,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 break;
            case Ast::FINAL:
                 if (access_flags.ACC_FINAL())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_FINAL();

                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::FINAL_ABSTRACT_CLASS,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 break;
            case Ast::PUBLIC:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PUBLIC();
                 break;
            case Ast::PRIVATE:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PRIVATE();
                 break;
            case Ast::PROTECTED:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PROTECTED();
                 break;
            case Ast::STATIC:
                 if (access_flags.ACC_STATIC())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_STATIC();
                 break;
            case Ast::STRICTFP:
                 if (access_flags.ACC_STRICTFP())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_STRICTFP();
                 break;
            default:
                 ReportSemError(SemanticError::INVALID_INNER_CLASS_MODIFIER,
                                modifier -> modifier_kind_token,
                                modifier -> modifier_kind_token,
                                lex_stream -> Name(modifier -> modifier_kind_token));
                 break;
        }
    }

    return access_flags;
}


AccessFlags Semantic::ProcessStaticNestedClassModifiers(AstClassDeclaration *class_declaration)
{
    AccessFlags access_flags;

    for (int i = 0; i < class_declaration -> NumClassModifiers(); i++)
    {
        AstModifier *modifier = class_declaration -> ClassModifier(i);

        switch(modifier -> kind)
        {
            case Ast::ABSTRACT:
                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_ABSTRACT();

                 if (access_flags.ACC_FINAL())
                 {
                     ReportSemError(SemanticError::FINAL_ABSTRACT_CLASS,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 break;
            case Ast::FINAL:
                 if (access_flags.ACC_FINAL())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_FINAL();

                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::FINAL_ABSTRACT_CLASS,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 break;
            case Ast::PUBLIC:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else
                 {
                     if (control.option.pedantic)
                         ReportSemError(SemanticError::REDUNDANT_PUBLIC,
                                        modifier -> modifier_kind_token,
                                        modifier -> modifier_kind_token);
                     access_flags.SetACC_PUBLIC();
                 }
                 break;
            case Ast::STATIC:
                 if (access_flags.ACC_STATIC())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else
                 {
                     if (control.option.pedantic)
                         ReportSemError(SemanticError::REDUNDANT_STATIC,
                                        modifier -> modifier_kind_token,
                                        modifier -> modifier_kind_token);
                     access_flags.SetACC_STATIC();
                 }
                 break;
            case Ast::STRICTFP:
                 if (access_flags.ACC_STRICTFP())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_STRICTFP();
                 break;
            default:
                 ReportSemError(SemanticError::INVALID_INNER_CLASS_MODIFIER,
                                modifier -> modifier_kind_token,
                                modifier -> modifier_kind_token,
                                lex_stream -> Name(modifier -> modifier_kind_token));
                 break;
        }
    }

    //
    // A type that is a member of an interface is implicitly deemed to
    // be static and public, whether it is explicitly marked so or not.
    //
    access_flags.SetACC_STATIC();
    access_flags.SetACC_PUBLIC();

    return access_flags;
}


AccessFlags Semantic::ProcessInterfaceModifiers(AstInterfaceDeclaration *interface_declaration)
{
    AccessFlags access_flags;

    for (int i = 0; i < interface_declaration -> NumInterfaceModifiers(); i++)
    {
        AstModifier *modifier = interface_declaration -> InterfaceModifier(i);

        switch(modifier -> kind)
        {
            case Ast::ABSTRACT:
                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else
                 {
                     ReportSemError(SemanticError::OBSOLESCENT_ABSTRACT,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                     access_flags.SetACC_ABSTRACT();
                 }
                 break;
            case Ast::PUBLIC:
                 if (access_flags.ACC_PUBLIC())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PUBLIC();
                 break;
            case Ast::STRICTFP:
                 if (access_flags.ACC_STRICTFP())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_STRICTFP();
                 break;
            default:
                 ReportSemError(SemanticError::INVALID_INTERFACE_MODIFIER,
                                modifier -> modifier_kind_token,
                                modifier -> modifier_kind_token,
                                lex_stream -> Name(modifier -> modifier_kind_token));
                 break;
        }
    }

    access_flags.SetACC_INTERFACE();
    access_flags.SetACC_ABSTRACT(); // every interface is implicitly abstract

    return access_flags;
}


AccessFlags Semantic::ProcessNestedInterfaceModifiers(AstInterfaceDeclaration *interface_declaration)
{
    AccessFlags access_flags;

    for (int i = 0; i < interface_declaration -> NumInterfaceModifiers(); i++)
    {
        AstModifier *modifier = interface_declaration -> InterfaceModifier(i);

        switch(modifier -> kind)
        {
            case Ast::ABSTRACT:
                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else
                 {
                     ReportSemError(SemanticError::OBSOLESCENT_ABSTRACT,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                     access_flags.SetACC_ABSTRACT();
                 }
                 break;
            case Ast::PUBLIC:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PUBLIC();
                 break;
            case Ast::PRIVATE:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PRIVATE();
                 break;
            case Ast::PROTECTED:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PROTECTED();
                 break;
            case Ast::STATIC: // TODO: Need to confirm that this is valid !!!
                 if (access_flags.ACC_STATIC())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else
                 {
                     if (control.option.pedantic)
                         ReportSemError(SemanticError::REDUNDANT_STATIC,
                                        modifier -> modifier_kind_token,
                                        modifier -> modifier_kind_token);
                     access_flags.SetACC_STATIC();
                 }
                 break;
            case Ast::STRICTFP:
                 if (access_flags.ACC_STRICTFP())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_STRICTFP();
                 break;
            default:
                 ReportSemError(SemanticError::INVALID_INTERFACE_MODIFIER,
                                modifier -> modifier_kind_token,
                                modifier -> modifier_kind_token,
                                lex_stream -> Name(modifier -> modifier_kind_token));
                 break;
        }
    }

    access_flags.SetACC_INTERFACE();
    access_flags.SetACC_ABSTRACT(); // every interface is implicitly abstract
    access_flags.SetACC_STATIC();   // every inner interface is implicitly static

    return access_flags;
}


AccessFlags Semantic::ProcessFieldModifiers(AstFieldDeclaration *field_declaration)
{
    AccessFlags access_flags;

    for (int i = 0; i < field_declaration -> NumVariableModifiers(); i++)
    {
        AstModifier *modifier = field_declaration -> VariableModifier(i);

        switch(modifier -> kind)
        {
            case Ast::PUBLIC:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PUBLIC();
                 break;
            case Ast::PROTECTED:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PROTECTED();
                 break;
            case Ast::PRIVATE:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PRIVATE();
                 break;
            case Ast::STATIC:
                 if (access_flags.ACC_STATIC())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_STATIC();
                 break;
            case Ast::FINAL:
                 if (access_flags.ACC_FINAL())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_FINAL();

                 if (access_flags.ACC_VOLATILE())
                 {
                     ReportSemError(SemanticError::FINAL_VOLATILE,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 break;
            case Ast::TRANSIENT:
                 if (access_flags.ACC_TRANSIENT())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_TRANSIENT();
                 break;
            case Ast::VOLATILE:
                 if (access_flags.ACC_VOLATILE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_VOLATILE();

                 if (access_flags.ACC_FINAL())
                 {
                     ReportSemError(SemanticError::VOLATILE_FINAL,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 break;
            default:
                 ReportSemError(SemanticError::INVALID_FIELD_MODIFIER,
                                modifier -> modifier_kind_token,
                                modifier -> modifier_kind_token,
                                lex_stream -> Name(modifier -> modifier_kind_token));
                 break;
        }
    }

    return access_flags;
}


AccessFlags Semantic::ProcessLocalModifiers(AstLocalVariableDeclarationStatement *local_declaration)
{
    AccessFlags access_flags;

    for (int i = 0; i < local_declaration -> NumLocalModifiers(); i++)
    {
        AstModifier *modifier = local_declaration -> LocalModifier(i);

        if (modifier -> kind == Ast::FINAL)
        {
            if (access_flags.ACC_FINAL())
            {
                ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                               modifier -> modifier_kind_token,
                               modifier -> modifier_kind_token);
            }
            else access_flags.SetACC_FINAL();
        }
        else
        {
            ReportSemError(SemanticError::INVALID_LOCAL_MODIFIER,
                           modifier -> modifier_kind_token,
                           modifier -> modifier_kind_token,
                           lex_stream -> Name(modifier -> modifier_kind_token));
        }
    }

    return access_flags;
}


AccessFlags Semantic::ProcessFormalModifiers(AstFormalParameter *parameter_declaration)
{
    AccessFlags access_flags;

    for (int i = 0; i < parameter_declaration -> NumParameterModifiers(); i++)
    {
        AstModifier *modifier = parameter_declaration -> ParameterModifier(i);

        if (modifier -> kind == Ast::FINAL)
        {
            if (access_flags.ACC_FINAL())
            {
                ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                               modifier -> modifier_kind_token,
                               modifier -> modifier_kind_token);
            }
            else access_flags.SetACC_FINAL();
        }
        else
        {
            ReportSemError(SemanticError::INVALID_LOCAL_MODIFIER,
                           modifier -> modifier_kind_token,
                           modifier -> modifier_kind_token,
                           lex_stream -> Name(modifier -> modifier_kind_token));
        }
    }

    return access_flags;
}


AccessFlags Semantic::ProcessMethodModifiers(AstMethodDeclaration *method_declaration)
{
    AccessFlags access_flags;

    for (int i = 0; i < method_declaration -> NumMethodModifiers(); i++)
    {
        AstModifier *modifier = method_declaration -> MethodModifier(i);

        switch(modifier -> kind)
        {
            case Ast::PUBLIC:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PUBLIC();
                 break;
            case Ast::PROTECTED:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PROTECTED();
                 break;
            case Ast::PRIVATE:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PRIVATE();

                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::ABSTRACT_METHOD_MODIFIER_CONFLICT,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token,
                                    lex_stream -> Name(modifier -> modifier_kind_token));
                 }
                 break;
            case Ast::STATIC:
                 if (access_flags.ACC_STATIC())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_STATIC();

                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::ABSTRACT_METHOD_MODIFIER_CONFLICT,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token,
                                    lex_stream -> Name(modifier -> modifier_kind_token));
                 }
                 break;
            case Ast::STRICTFP:
                 if (access_flags.ACC_STRICTFP())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_STRICTFP();
                 break;
            case Ast::ABSTRACT:
                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_ABSTRACT();

                 if (access_flags.ACC_PRIVATE() || access_flags.ACC_STATIC() ||
                     access_flags.ACC_FINAL()   || access_flags.ACC_NATIVE() || access_flags.ACC_SYNCHRONIZED())
                 {
                     ReportSemError(SemanticError::BAD_ABSTRACT_METHOD_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 break;
            case Ast::FINAL:
                 if (access_flags.ACC_FINAL())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_FINAL();

                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::ABSTRACT_METHOD_MODIFIER_CONFLICT,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token,
                                    lex_stream -> Name(modifier -> modifier_kind_token));
                 }
                 break;
            case Ast::NATIVE:
                 if (access_flags.ACC_NATIVE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_NATIVE();

                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::ABSTRACT_METHOD_MODIFIER_CONFLICT,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token,
                                    lex_stream -> Name(modifier -> modifier_kind_token));
                 }
                 break;
            case Ast::SYNCHRONIZED:
                 if (access_flags.ACC_SYNCHRONIZED())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_SYNCHRONIZED();

                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::ABSTRACT_METHOD_MODIFIER_CONFLICT,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token,
                                    lex_stream -> Name(modifier -> modifier_kind_token));
                 }
                 break;
            default:
                 ReportSemError(SemanticError::INVALID_METHOD_MODIFIER,
                                modifier -> modifier_kind_token,
                                modifier -> modifier_kind_token,
                                lex_stream -> Name(modifier -> modifier_kind_token));
                 break;
        }
    }

    return access_flags;
}


AccessFlags Semantic::ProcessAbstractMethodModifiers(AstMethodDeclaration *method_declaration)
{
    AccessFlags access_flags;

    for (int i = 0; i < method_declaration -> NumMethodModifiers(); i++)
    {
        AstModifier *modifier = method_declaration -> MethodModifier(i);

        switch(modifier -> kind)
        {
            case Ast::PUBLIC:
                 if (access_flags.ACC_PUBLIC())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else
                 {
                     if (control.option.pedantic)
                         ReportSemError(SemanticError::REDUNDANT_PUBLIC,
                                        modifier -> modifier_kind_token,
                                        modifier -> modifier_kind_token);
                     access_flags.SetACC_PUBLIC();
                 }
                 break;
            case Ast::ABSTRACT:
                 if (access_flags.ACC_ABSTRACT())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else
                 {
                     if (control.option.pedantic)
                         ReportSemError(SemanticError::REDUNDANT_ABSTRACT,
                                        modifier -> modifier_kind_token,
                                        modifier -> modifier_kind_token);
                     access_flags.SetACC_ABSTRACT();
                 }
                 break;
            default:
                 ReportSemError(SemanticError::INVALID_SIGNATURE_MODIFIER,
                                modifier -> modifier_kind_token,
                                modifier -> modifier_kind_token,
                                lex_stream -> Name(modifier -> modifier_kind_token));
                 break;
        }
    }

    //
    // Every method declaration in the body of an interface is implicitly "public" and "abstract"
    //
    access_flags.SetACC_ABSTRACT();
    access_flags.SetACC_PUBLIC();

    return access_flags;
}


AccessFlags Semantic::ProcessConstructorModifiers(AstConstructorDeclaration *constructor_declaration)
{
    AccessFlags access_flags;

    for (int i = 0; i < constructor_declaration -> NumConstructorModifiers(); i++)
    {
        AstModifier *modifier = constructor_declaration -> ConstructorModifier(i);

        switch(modifier -> kind)
        {
            case Ast::PUBLIC:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PUBLIC();
                 break;
            case Ast::PROTECTED:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PROTECTED();
                 break;
            case Ast::PRIVATE:
                 if (access_flags.ACC_PUBLIC() || access_flags.ACC_PROTECTED() || access_flags.ACC_PRIVATE())
                 {
                     ReportSemError(SemanticError::DUPLICATE_ACCESS_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else access_flags.SetACC_PRIVATE();
                 break;
            default:
                 ReportSemError(SemanticError::INVALID_CONSTRUCTOR_MODIFIER,
                                modifier -> modifier_kind_token,
                                modifier -> modifier_kind_token,
                                lex_stream -> Name(modifier -> modifier_kind_token));
                 break;
        }
    }

    return access_flags;
}


AccessFlags Semantic::ProcessConstantModifiers(AstFieldDeclaration *field_declaration)
{
    AccessFlags access_flags;

    for (int i = 0; i < field_declaration -> NumVariableModifiers(); i++)
    {
        AstModifier *modifier = field_declaration -> VariableModifier(i);

        switch(modifier -> kind)
        {
            case Ast::PUBLIC:
                 if (access_flags.ACC_PUBLIC())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else
                 {
                     if (control.option.pedantic)
                         ReportSemError(SemanticError::REDUNDANT_PUBLIC,
                                        modifier -> modifier_kind_token,
                                        modifier -> modifier_kind_token);
                     access_flags.SetACC_PUBLIC();
                 }
                 break;
            case Ast::STATIC:
                 if (access_flags.ACC_STATIC())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else
                 {
                     if (control.option.pedantic)
                         ReportSemError(SemanticError::REDUNDANT_STATIC,
                                        modifier -> modifier_kind_token,
                                        modifier -> modifier_kind_token);
                     access_flags.SetACC_STATIC();
                 }
                 break;
            case Ast::FINAL:
                 if (access_flags.ACC_FINAL())
                 {
                     ReportSemError(SemanticError::DUPLICATE_MODIFIER,
                                    modifier -> modifier_kind_token,
                                    modifier -> modifier_kind_token);
                 }
                 else
                 {
                     if (control.option.pedantic)
                         ReportSemError(SemanticError::REDUNDANT_FINAL,
                                        modifier -> modifier_kind_token,
                                        modifier -> modifier_kind_token);
                     access_flags.SetACC_FINAL();
                 }
                 break;
            default:
                 ReportSemError(SemanticError::INVALID_CONSTANT_MODIFIER,
                                modifier -> modifier_kind_token,
                                modifier -> modifier_kind_token,
                                lex_stream -> Name(modifier -> modifier_kind_token));
                 break;
        }
    }

    //
    // Every constant (field) declaration in the body of an interface is implicitly "public", "static" and "final"
    //
    access_flags.SetACC_PUBLIC();
    access_flags.SetACC_STATIC();
    access_flags.SetACC_FINAL();

    return access_flags;
}