// $Id: decl.cpp,v 1.15 1999/03/09 14:37:15 shields Exp $
copyright notice

#include "config.h"
#include <sys/stat.h>
#include "semantic.h"
#include "control.h"
#include "depend.h"
#include "table.h"
#include "tuple.h"

//
// If this compilation unit contains a package declaration, make sure the package
// is associated with a directory and that the name of the package is not also
// associated with a type.
//
inline void Semantic::CheckPackage()
{
    if (compilation_unit -> package_declaration_opt)
    {
        //
        // Make sure that the package actually exists.
        //
        if (this_package -> directory.Length() == 0 && control.option.directory == NULL)
        {
            ReportSemError(SemanticError::PACKAGE_NOT_FOUND,
                           compilation_unit -> package_declaration_opt -> name -> LeftToken(),
                           compilation_unit -> package_declaration_opt -> name -> RightToken(),
                           this_package -> PackageName());
        }
        else
        {
            //
            // Make sure that the package or any of its parents does not match the name of a type.
            //
            AstPackageDeclaration *package_declaration = compilation_unit -> package_declaration_opt;
            AstExpression *name = FindFirstType(package_declaration -> name);
            TypeSymbol *type = name -> symbol -> TypeCast();
            if (type && (! type -> Bad()))
            {
assert(type -> file_symbol);
                char *file_name = type -> file_symbol -> FileName();
                int length = type -> file_symbol -> FileNameLength();
                wchar_t *error_name = new wchar_t[length + 1];
                for (int i = 0; i < length; i++)
                    error_name[i] = file_name[i];
                error_name[length] = U_NULL;

                ReportSemError(SemanticError::PACKAGE_TYPE_CONFLICT,
                               name -> LeftToken(),
                               name -> RightToken(),
                               type -> ContainingPackage() -> PackageName(),
                               type -> Name(),
                               error_name);

                delete [] error_name;
            }
        }
    }

    return;
}


//
// Pass 1: Introduce the main package, the current package and all types specified into their proper scope
//
void Semantic::ProcessTypeNames()
{
    import_on_demand_packages.Next() = control.system_package;
    compilation_unit = source_file_symbol -> compilation_unit;

    //
    // If we are supposed to be verbose, report empty declarations...
    //
    if (control.option.pedantic)
    {
        if (compilation_unit -> EmptyCompilationUnitCast())
        {
            ReportSemError(SemanticError::NO_TYPES,
                           compilation_unit -> LeftToken(),
                           compilation_unit -> RightToken());
        }

        for (int i = 0; i < compilation_unit -> NumTypeDeclarations(); i++)
        {
            Ast *type_declaration = compilation_unit -> TypeDeclaration(i);
            if (type_declaration -> EmptyDeclarationCast())
            {
                ReportSemError(SemanticError::EMPTY_DECLARATION,
                               type_declaration -> LeftToken(),
                               type_declaration -> RightToken());
            }
        }
    }

    //
    // If we have a bad compilation unit insert its types as "bad types"
    //
    if (compilation_unit -> BadCompilationUnitCast())
    {
        for (int i = 0; i < lex_stream -> NumTypes(); i++)
        {
            LexStream::TokenIndex identifier_token = lex_stream -> Next(lex_stream -> Type(i));
            if (lex_stream -> Kind(identifier_token) == TK_Identifier)
            {
                NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(identifier_token);
                TypeSymbol *type = this_package -> FindTypeSymbol(name_symbol);
assert(type);
                type -> MarkSourceNoLongerPending();
                type -> supertypes_closure = new SymbolSet;
                type -> subtypes = new SymbolSet;
                type -> semantic_environment = new SemanticEnvironment((Semantic *) this, type, NULL);
                if (type != control.Object())
                    type -> super = (type == control.Throwable() ? control.Object() : control.Throwable());
                type -> MarkBad();
                AddDefaultConstructor(type);
                source_file_symbol -> types.Next() = type;
            }
        }

        return;
    }

    //
    // Process each type in this compilation unit, in turn
    //
    for (int k = 0; k < compilation_unit -> NumTypeDeclarations(); k++)
    {
        LexStream::TokenIndex identifier_token;
        TypeSymbol *type = NULL;

        Ast *type_declaration = compilation_unit -> TypeDeclaration(k);
        switch(type_declaration -> kind)
        {
            case Ast::CLASS:
            {
                AstClassDeclaration *class_declaration = (AstClassDeclaration *) type_declaration;
                identifier_token = class_declaration -> identifier_token;
                NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(identifier_token);

                type = this_package -> FindTypeSymbol(name_symbol);
                if (type)
                {
                    if (! type -> SourcePending())
                    {
                        ReportSemError(SemanticError::DUPLICATE_TYPE_DECLARATION,
                                       identifier_token,
                                       identifier_token,
                                       name_symbol -> Name(),
                                       type -> FileLoc());
                        type = NULL;
                    }
                    else
                    {
                        if (type -> ContainingPackage() == control.unnamed_package)
                        {
                            TypeSymbol *old_type = (TypeSymbol *) control.unnamed_package_types.Image(name_symbol);
                            if (old_type != type)
                            {
                                ReportSemError(SemanticError::DUPLICATE_TYPE_DECLARATION,
                                               identifier_token,
                                               identifier_token,
                                               name_symbol -> Name(),
                                               old_type -> FileLoc());
                            }
                        }

                        type -> MarkSourceNoLongerPending();
                        type -> semantic_environment = new SemanticEnvironment((Semantic *) this, type, NULL);
                        type -> supertypes_closure = new SymbolSet;
                        type -> subtypes = new SymbolSet;
                        type -> declaration = class_declaration;
                        type -> SetFlags(ProcessClassModifiers(class_declaration));
                        //
                        // Add 3 extra elements for padding. May need a default constructor and other support elements.
                        //
                        type -> SetSymbolTable(class_declaration -> class_body -> NumClassBodyDeclarations() + 3);
                        type -> SetLocation();

                        source_file_symbol -> types.Next() = type;
                        class_declaration -> semantic_environment = type -> semantic_environment; // save for processing bodies later.

                        CheckClassMembers(type, class_declaration -> class_body);
                    }
                }

                break;
            }
            case Ast::INTERFACE:
            {
                AstInterfaceDeclaration *interface_declaration = (AstInterfaceDeclaration *) type_declaration;
                identifier_token = interface_declaration -> identifier_token;
                NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(identifier_token);

                type = this_package -> FindTypeSymbol(name_symbol);
                if (type)
                {
                    if (! type -> SourcePending())
                    {
                        ReportSemError(SemanticError::DUPLICATE_TYPE_DECLARATION,
                                       identifier_token,
                                       identifier_token,
                                       name_symbol -> Name(),
                                       type -> FileLoc());
                        type = NULL;
                    }
                    else
                    {
                        if (type -> ContainingPackage() == control.unnamed_package)
                        {
                            TypeSymbol *old_type = (TypeSymbol *) control.unnamed_package_types.Image(name_symbol);
                            if (old_type != type)
                            {
                                ReportSemError(SemanticError::DUPLICATE_TYPE_DECLARATION,
                                               identifier_token,
                                               identifier_token,
                                               name_symbol -> Name(),
                                               old_type -> FileLoc());
                            }
                        }

                        type -> MarkSourceNoLongerPending();
                        type -> semantic_environment = new SemanticEnvironment((Semantic *) this, type, NULL);
                        type -> supertypes_closure = new SymbolSet;
                        type -> subtypes = new SymbolSet;
                        type -> declaration = interface_declaration;
                        type -> file_symbol = source_file_symbol;
                        type -> SetFlags(ProcessInterfaceModifiers(interface_declaration));
                        type -> SetSymbolTable(interface_declaration -> NumInterfaceMemberDeclarations());
                        type -> SetLocation();

                        source_file_symbol -> types.Next() = type;
                        interface_declaration -> semantic_environment = type -> semantic_environment;

                        CheckInterfaceMembers(type, interface_declaration);
                    }
                }
                break;
            }
        }

        //
        // If we successfully processed this type, check that
        //     . its name does not conflict with a subpackage
        //     . if it is contained in a file with a diffent name
        //       than its own name that there does not also exist a
        //       (java or class) file with its name.
        //
        if (type)
        {
            NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(identifier_token);
            for (int i = 0; i < this_package -> directory.Length(); i++)
            {
                if (this_package -> directory[i] -> FindDirectorySymbol(name_symbol))
                {
                    char *file_name = type -> file_symbol -> FileName();
                    int length = type -> file_symbol -> FileNameLength();
                    wchar_t *error_name = new wchar_t[length + 1];
                    for (int j = 0; j < length; j++)
                        error_name[j] = file_name[j];
                    error_name[length] = U_NULL;

                    ReportSemError(SemanticError::PACKAGE_TYPE_CONFLICT,
                                   identifier_token,
                                   identifier_token,
                                   this_package -> PackageName(),
                                   name_symbol -> Name(),
                                   error_name);

                    delete [] error_name;
                }
            }

            if (type -> Identity() != source_file_symbol -> Identity())
            {
                PackageSymbol *package = this_package;
                FileSymbol *file_symbol = Control::GetJavaFile(package, type -> Identity());

                if (file_symbol)
                {
                    ReportSemError(SemanticError::TYPE_IN_MULTIPLE_FILES,
                                   identifier_token,
                                   identifier_token,
                                   this_package -> PackageName(),
                                   source_file_symbol -> Name(),
                                   package -> PackageName(),
                                   type -> Name());
                }
            }
        }
    }

    CheckPackage();
    ProcessImports();
    ProcessSuperTypes();

    return;
}


void Semantic::CheckClassMembers(TypeSymbol *containing_type, AstClassBody *class_body)
{
    for (int i = 0; i < class_body -> NumNestedClasses(); i++)
    {
        AstClassDeclaration *class_declaration = class_body -> NestedClass(i);

        if (! control.option.one_one)
        {
             ReportSemError(SemanticError::ONE_ONE_FEATURE,
                            class_declaration -> LeftToken(),
                            class_declaration -> RightToken());
        }

        ProcessNestedClassName(containing_type, class_declaration);
    }

    for (int j = 0; j < class_body -> NumNestedInterfaces(); j++)
    {
        AstInterfaceDeclaration *interface_declaration = class_body -> NestedInterface(j);

        if (! control.option.one_one)
        {
            ReportSemError(SemanticError::ONE_ONE_FEATURE,
                           interface_declaration -> LeftToken(),
                           interface_declaration -> RightToken());
        }

        ProcessNestedInterfaceName(containing_type, interface_declaration);
    }

    for (int k = 0; k < class_body -> NumBlocks(); k++)
    {
        if (! control.option.one_one)
        {
            ReportSemError(SemanticError::ONE_ONE_FEATURE,
                           class_body -> Block(k) -> LeftToken(),
                           class_body -> Block(k) -> RightToken());
        }
    }

    for (int l = 0; l < class_body -> NumEmptyDeclarations(); l++)
    {
        if (control.option.pedantic)
        {
            ReportSemError(SemanticError::EMPTY_DECLARATION,
                           class_body -> EmptyDeclaration(l) -> LeftToken(),
                           class_body -> EmptyDeclaration(l) -> RightToken());
        }
    }

    return;
}


inline TypeSymbol *Semantic::FindTypeInShadow(TypeShadowSymbol *type_shadow_symbol, LexStream::TokenIndex identifier_token)
{
    //
    // Recall that even an inaccessible member x of a super class (or interface) S,
    // in addition to not been inherited by a subclass, hides all other occurrences of x that may
    // appear in a super class (or super interface) of S (see 8.3).
    //
    TypeSymbol *type_symbol = type_shadow_symbol -> type_symbol;

    for (int i = 0; i < type_shadow_symbol -> NumConflicts(); i++)
    {
        ReportSemError(SemanticError::AMBIGUOUS_NAME,
                       identifier_token,
                       identifier_token,
                       type_symbol -> Name(),
                       type_symbol -> owner -> TypeCast() -> ContainingPackage() -> PackageName(),
                       type_symbol -> owner -> TypeCast() -> ExternalName(),
                       type_shadow_symbol -> Conflict(i) -> owner -> TypeCast() -> ContainingPackage() -> PackageName(),
                       type_shadow_symbol -> Conflict(i) -> owner -> TypeCast() -> ExternalName());
    }

    return type_symbol;
}


//
// Look for a type within an environment stack, without regard to inheritance !!!
//
TypeSymbol *Semantic::FindTypeInEnvironment(SemanticEnvironment *env_stack, NameSymbol *name_symbol)
{
    for (SemanticEnvironment *env = env_stack; env; env = env -> previous)
    {
        TypeSymbol *type = env -> symbol_table.FindTypeSymbol(name_symbol);
        if (type)
            return type;
        type = env -> Type() -> FindTypeSymbol(name_symbol);
        if (type)
            return type;
        if (name_symbol == env -> Type() -> Identity())
            return env -> Type();
    }

    return (TypeSymbol *) NULL;
}


void Semantic::CheckNestedTypeDuplication(SemanticEnvironment *env, LexStream::TokenIndex identifier_token)
{
    NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(identifier_token);

    //
    // First check to see if we have a duplication at the same level...
    //
    TypeSymbol *old_type = (env -> symbol_table.Size() > 0 ? env -> symbol_table.Top() -> FindTypeSymbol(name_symbol)
                                                           : env -> Type() -> FindTypeSymbol(name_symbol));
    if (old_type)
    {
        ReportSemError(SemanticError::DUPLICATE_TYPE_DECLARATION,
                       identifier_token,
                       identifier_token,
                       name_symbol -> Name(),
                       old_type -> FileLoc());
    }
    else if (env -> symbol_table.Size() > 0)
    {
        old_type = env -> symbol_table.FindTypeSymbol(name_symbol); // check the whole stack !
        if (old_type)
        {
            ReportSemError(SemanticError::DUPLICATE_LOCAL_TYPE_DECLARATION,
                           identifier_token,
                           identifier_token,
                           name_symbol -> Name(),
                           old_type -> FileLoc());
        }
    }
    else if (env -> Type() -> Identity() == name_symbol)
    {
        ReportSemError(SemanticError::DUPLICATE_INNER_TYPE_NAME,
                       identifier_token,
                       identifier_token,
                       name_symbol -> Name(),
                       env -> Type() -> FileLoc());
    }
    else
    {
        //
        // ... Then check the enclosing environments...
        //
        for (env = env -> previous; env; env = env -> previous)
        {
            TypeSymbol *old_type = (env -> symbol_table.Size() > 0
                                         ? env -> symbol_table.FindTypeSymbol(name_symbol)
                                         : (TypeSymbol *) NULL);
            if (old_type)
            {
                ReportSemError(SemanticError::DUPLICATE_LOCAL_TYPE_DECLARATION,
                               identifier_token,
                               identifier_token,
                               name_symbol -> Name());
                break;
            }
            else if (env -> Type() -> Identity() == name_symbol)
            {
                ReportSemError(SemanticError::DUPLICATE_INNER_TYPE_NAME,
                               identifier_token,
                               identifier_token,
                               name_symbol -> Name(),
                               env -> Type() -> FileLoc());
                break;
            }
        }
    }

    return;
}


TypeSymbol *Semantic::ProcessNestedClassName(TypeSymbol *containing_type, AstClassDeclaration *class_declaration)
{
    CheckNestedTypeDuplication(containing_type -> semantic_environment, class_declaration -> identifier_token);

    NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(class_declaration -> identifier_token);
    TypeSymbol *outermost_type = containing_type -> outermost_type;

    int length = containing_type -> ExternalNameLength() + 1 + name_symbol -> NameLength(); // +1 for $,... +1 for $
    wchar_t *external_name = new wchar_t[length + 1]; // +1 for '\0';
    wcscpy(external_name, containing_type -> ExternalName());
    wcscat(external_name, StringConstant::US__DS_);
    wcscat(external_name, name_symbol -> Name());

    TypeSymbol *inner_type = containing_type -> InsertNestedTypeSymbol(name_symbol);
    inner_type -> outermost_type = outermost_type;
    inner_type -> supertypes_closure = new SymbolSet;
    inner_type -> subtypes = new SymbolSet;
    inner_type -> SetExternalIdentity(control.FindOrInsertName(external_name, length));
    inner_type -> semantic_environment = new SemanticEnvironment((Semantic *) this,
                                                                 inner_type,
                                                                 containing_type -> semantic_environment);
    inner_type -> declaration = class_declaration;
    inner_type -> file_symbol = source_file_symbol;
    inner_type -> SetFlags(containing_type -> ACC_INTERFACE()
                                            ? ProcessStaticNestedClassModifiers(class_declaration)
                                            : ProcessNestedClassModifiers(class_declaration));
    inner_type -> SetOwner(containing_type);
    //
    // Add 3 extra elements for padding. May need a default constructor and other support elements.
    //
    inner_type -> SetSymbolTable(class_declaration -> class_body -> NumClassBodyDeclarations() + 3);
    inner_type -> SetLocation();
    inner_type -> SetSignature(control);

    //
    // If not a top-level type, then add pointer to enclosing type.
    //
    if (! inner_type -> ACC_STATIC())
        inner_type -> InsertThis(0);

    if (inner_type -> IsLocal())
    {
        if (! outermost_type -> local)
            outermost_type -> local = new SymbolSet;
        outermost_type -> local -> AddElement(inner_type);
    }
    else
    {
        if (! outermost_type -> non_local)
            outermost_type -> non_local = new SymbolSet;
        outermost_type -> non_local -> AddElement(inner_type);
    }

    class_declaration -> semantic_environment = inner_type -> semantic_environment; // save for processing bodies later.

    CheckClassMembers(inner_type, class_declaration -> class_body);

    delete [] external_name;

    return inner_type;
}


void Semantic::CheckInterfaceMembers(TypeSymbol *containing_type, AstInterfaceDeclaration *interface_declaration)
{
    for (int i = 0; i < interface_declaration -> NumNestedClasses(); i++)
    {
        AstClassDeclaration *class_declaration = interface_declaration -> NestedClass(i);

        if (! control.option.one_one)
        {
             ReportSemError(SemanticError::ONE_ONE_FEATURE,
                            class_declaration -> LeftToken(),
                            class_declaration -> RightToken());
        }

        ProcessNestedClassName(containing_type, class_declaration);
    }

    for (int j = 0; j < interface_declaration -> NumNestedInterfaces(); j++)
    {
        AstInterfaceDeclaration *inner_interface_declaration = interface_declaration -> NestedInterface(j);

        if (! control.option.one_one)
        {
            ReportSemError(SemanticError::ONE_ONE_FEATURE,
                           inner_interface_declaration -> LeftToken(),
                           inner_interface_declaration -> RightToken());
        }

        ProcessNestedInterfaceName(containing_type, inner_interface_declaration);
    }

    for (int l = 0; l < interface_declaration -> NumEmptyDeclarations(); l++)
    {
        if (control.option.pedantic)
        {
            ReportSemError(SemanticError::EMPTY_DECLARATION,
                           interface_declaration -> EmptyDeclaration(l) -> LeftToken(),
                           interface_declaration -> EmptyDeclaration(l) -> RightToken());
        }
    }

    return;
}


TypeSymbol *Semantic::ProcessNestedInterfaceName(TypeSymbol *containing_type, AstInterfaceDeclaration *interface_declaration)
{
    CheckNestedTypeDuplication(containing_type -> semantic_environment, interface_declaration -> identifier_token);

    NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(interface_declaration -> identifier_token);
    TypeSymbol *outermost_type = containing_type -> outermost_type;

    int length = containing_type -> ExternalNameLength() + 1 + name_symbol -> NameLength(); // +1 for $,... +1 for $
    wchar_t *external_name = new wchar_t[length + 1]; // +1 for '\0';
    wcscpy(external_name, containing_type -> ExternalName());
    wcscat(external_name, StringConstant::US__DS_);
    wcscat(external_name, name_symbol -> Name());

    TypeSymbol *inner_type = containing_type -> InsertNestedTypeSymbol(name_symbol);
    inner_type -> outermost_type = outermost_type;
    inner_type -> supertypes_closure = new SymbolSet;
    inner_type -> subtypes = new SymbolSet;
    inner_type -> SetExternalIdentity(control.FindOrInsertName(external_name, length));
    inner_type -> semantic_environment = new SemanticEnvironment((Semantic *) this,
                                                                 inner_type,
                                                                 containing_type -> semantic_environment);
    inner_type -> declaration = interface_declaration;
    inner_type -> file_symbol = source_file_symbol;
    inner_type -> SetFlags(ProcessNestedInterfaceModifiers(interface_declaration));
    inner_type -> SetOwner(containing_type);
    inner_type -> SetSymbolTable(interface_declaration -> NumInterfaceMemberDeclarations());
    inner_type -> SetLocation();
    inner_type -> SetSignature(control);

    if (inner_type -> IsLocal())
    {
        if (! outermost_type -> local)
            outermost_type -> local = new SymbolSet;
        outermost_type -> local -> AddElement(inner_type);
    }
    else
    {
        if (! outermost_type -> non_local)
            outermost_type -> non_local = new SymbolSet;
        outermost_type -> non_local -> AddElement(inner_type);
    }

    interface_declaration -> semantic_environment = inner_type -> semantic_environment; // save for processing bodies later.

    CheckInterfaceMembers(inner_type, interface_declaration);

    delete [] external_name;

    return inner_type;
}


//
// Pass 1.2: Process all import statements
//
void Semantic::ProcessImports()
{
    for (int i = 0; i < compilation_unit -> NumImportDeclarations(); i++)
    {
        AstImportDeclaration *import_declaration = compilation_unit -> ImportDeclaration(i);

        if (import_declaration -> star_token_opt)
             ProcessTypeImportOnDemandDeclaration(import_declaration);
        else ProcessSingleTypeImportDeclaration(import_declaration);
    }

    return;
}


//
// Pass 1.3: Process outer types in "extends" and "implements" clauses associated with the types.
//
void Semantic::ProcessSuperTypes()
{
    //
    // Process outer type of superclasses and interfaces and make sure that compilation unit
    // contains exactly one public type.
    //
    TypeSymbol *public_type = NULL;
    for (int i = 0; i < compilation_unit -> NumTypeDeclarations(); i++)
    {
        TypeSymbol *type = NULL;

        Ast *type_declaration = compilation_unit -> TypeDeclaration(i);
        switch(type_declaration -> kind)
        {
            case Ast::CLASS:
            {
                AstClassDeclaration *class_declaration = (AstClassDeclaration *) type_declaration;
                if (class_declaration -> semantic_environment)
                {
                    type = class_declaration -> semantic_environment -> Type();
                    if (class_declaration -> super_opt)
                    {
                        TypeSymbol *super_type = FindFirstType(class_declaration -> super_opt) -> symbol -> TypeCast();
                        if (super_type)
                            super_type -> subtypes -> AddElement(type);
                    }

                    for (int k = 0; k < class_declaration -> NumInterfaces(); k++)
                    {
                        TypeSymbol *super_type = FindFirstType(class_declaration -> Interface(k)) -> symbol -> TypeCast();
                        if (super_type)
{
assert(super_type -> subtypes);
                            super_type -> subtypes -> AddElement(type);
}
                    }

                    ProcessOuterType(class_declaration);
                }
                break;
            }
            case Ast::INTERFACE:
            {
                AstInterfaceDeclaration *interface_declaration = (AstInterfaceDeclaration *) type_declaration;
                if (interface_declaration -> semantic_environment)
                {
                    type = interface_declaration -> semantic_environment -> Type();
                    for (int k = 0; k < interface_declaration -> NumExtendsInterfaces(); k++)
                    {
                        TypeSymbol *super_type = FindFirstType(interface_declaration -> ExtendsInterface(k)) -> symbol -> TypeCast();
                        if (super_type)
                            super_type -> subtypes -> AddElement(type);
                    }

                    ProcessOuterType(interface_declaration);
                }
                break;
            }
            default:
                break;
        }

        if (type && type -> ACC_PUBLIC())
        {
            if (! public_type)
            {
                public_type = type;

                if  (source_file_symbol -> Identity() != public_type -> Identity())
                {
                    if (type -> ACC_INTERFACE())
                    {
                        AstInterfaceDeclaration *interface_declaration = (AstInterfaceDeclaration *) type_declaration;
                        ReportSemError(SemanticError::MISMATCHED_TYPE_AND_FILE_NAMES,
                                       interface_declaration -> identifier_token,
                                       interface_declaration -> identifier_token,
                                       public_type -> Name());
                    }
                    else
                    {
                        AstClassDeclaration *class_declaration = (AstClassDeclaration *) type_declaration;
                        ReportSemError(SemanticError::MISMATCHED_TYPE_AND_FILE_NAMES,
                                       class_declaration -> identifier_token,
                                       class_declaration -> identifier_token,
                                       public_type -> Name());
                    }
                }
            }
            else
            {
                if (type -> ACC_INTERFACE())
                {
                    AstInterfaceDeclaration *interface_declaration = (AstInterfaceDeclaration *) type_declaration;
                    ReportSemError(SemanticError::MULTIPLE_PUBLIC_TYPES,
                                   interface_declaration -> identifier_token,
                                   interface_declaration -> identifier_token,
                                   type -> Name(),
                                   public_type -> Name());
                }
                else
                {
                    AstClassDeclaration *class_declaration = (AstClassDeclaration *) type_declaration;
                    ReportSemError(SemanticError::MULTIPLE_PUBLIC_TYPES,
                                   class_declaration -> identifier_token,
                                   class_declaration -> identifier_token,
                                   type -> Name(),
                                   public_type -> Name());
                }
            }
        }
    }

    return;
}


void Semantic::ProcessOuterType(AstClassDeclaration *class_declaration)
{
    TypeSymbol *type = class_declaration -> semantic_environment -> Type();

    //
    // If a type has no super type, set it up properly in case
    // it is expanded prematurely by one of its dependents.
    //
    if (! class_declaration -> super_opt && class_declaration -> NumInterfaces() == 0)
    {
        if (type -> Identity() != control.object_name_symbol ||
            type -> ContainingPackage() != control.system_package || type -> IsNested())
            type -> super = control.Object();
    }

    AstClassBody *class_body = class_declaration -> class_body;
    for (int i = 0; i < class_body -> NumNestedClasses(); i++)
    {
        AstClassDeclaration *inner_class_declaration = class_body -> NestedClass(i);
        if (inner_class_declaration -> semantic_environment)
            ProcessOuterType(inner_class_declaration);
    }

    for (int j = 0; j < class_body -> NumNestedInterfaces(); j++)
    {
        AstInterfaceDeclaration *inner_interface_declaration = class_body -> NestedInterface(j);
        if (inner_interface_declaration -> semantic_environment)
            ProcessOuterType(inner_interface_declaration);
    }

    return;
}


void Semantic::ProcessOuterType(AstInterfaceDeclaration *interface_declaration)
{
    TypeSymbol *type = interface_declaration -> semantic_environment -> Type();

    //
    // Set it up an interface properly in case it is 
    // expanded prematurely by one of its dependents.
    //
    type -> super = control.Object();

    for (int i = 0; i < interface_declaration -> NumNestedClasses(); i++)
    {
        AstClassDeclaration *inner_class_declaration = interface_declaration -> NestedClass(i);
        if (inner_class_declaration -> semantic_environment)
            ProcessOuterType(inner_class_declaration);
    }

    for (int j = 0; j < interface_declaration -> NumNestedInterfaces(); j++)
    {
        AstInterfaceDeclaration *inner_interface_declaration = interface_declaration -> NestedInterface(j);
        if (inner_interface_declaration -> semantic_environment)
            ProcessOuterType(inner_interface_declaration);
    }

    return;
}


//
// Pass 2: Process "extends" and "implements" clauses associated with the types.
//
void Semantic::ProcessTypeHeader(AstClassDeclaration *class_declaration)
{
    state_stack.Push(class_declaration -> semantic_environment);
    TypeSymbol *this_type = ThisType();
assert(! this_type -> HeaderProcessed() || this_type -> Bad());

    if (! class_declaration -> super_opt)
    {
        if (this_type -> Identity() != control.object_name_symbol ||
            this_package != control.system_package || this_type -> IsNested())
            SetObjectSuperType(this_type, class_declaration -> identifier_token);
    }
    else
    {
        TypeSymbol *super_type = MustFindType(class_declaration -> super_opt);

assert(this_type -> subtypes_closure);
assert(! super_type -> SourcePending());

        this_type -> super = super_type;

        if (this_type -> subtypes_closure -> IsElement(super_type)) // if there is a cycle, break it and issue an error message
        {
            this_type -> super = control.Object();
            this_type -> MarkCircular();
            ReportSemError(SemanticError::CIRCULAR_CLASS,
                           class_declaration -> identifier_token,
                           class_declaration -> super_opt -> RightToken(),
                           this_type -> ContainingPackage() -> PackageName(),
                           this_type -> ExternalName());
        }
        else if (this_type -> Identity() == control.object_name_symbol &&
                 this_package == control.system_package && (! this_type -> IsNested()))
        {
             ReportSemError(SemanticError::OBJECT_WITH_SUPER_TYPE,
                            class_declaration -> super_opt -> LeftToken(),
                            class_declaration -> super_opt -> RightToken(),
                            this_type -> ContainingPackage() -> PackageName(),
                            this_type -> ExternalName());
             this_type -> super = NULL;
        }
        else if (this_type -> super -> ACC_INTERFACE())
        {
            ReportSemError(SemanticError::NOT_A_CLASS,
                           class_declaration -> super_opt -> LeftToken(),
                           class_declaration -> super_opt -> RightToken(),
                           this_type -> super -> ContainingPackage() -> PackageName(),
                           this_type -> super -> ExternalName());

            SetObjectSuperType(this_type, class_declaration -> identifier_token);
        }
        else if (this_type -> super -> ACC_FINAL())
        {
             ReportSemError(SemanticError::SUPER_IS_FINAL,
                            class_declaration -> super_opt -> LeftToken(),
                            class_declaration -> super_opt -> RightToken(),
                            this_type -> super -> ContainingPackage() -> PackageName(),
                            this_type -> super -> ExternalName());
        }
    }

    for (int i = 0; i < class_declaration -> NumInterfaces(); i++)
        ProcessInterface(class_declaration -> Interface(i));

    this_type -> MarkHeaderProcessed();

    state_stack.Pop();

    return;
}


void Semantic::ProcessTypeHeader(AstInterfaceDeclaration *interface_declaration)
{
    state_stack.Push(interface_declaration -> semantic_environment);
    TypeSymbol *this_type = ThisType();
assert(! this_type -> HeaderProcessed() || this_type -> Bad());

    SetObjectSuperType(this_type, interface_declaration -> identifier_token);
    for (int k = 0; k < interface_declaration -> NumExtendsInterfaces(); k++)
        ProcessInterface(interface_declaration -> ExtendsInterface(k));
assert(this_type -> subtypes_closure);
    for (int i = 0; i < this_type -> NumInterfaces(); i++)
    {
        if (this_type -> subtypes_closure -> IsElement(this_type -> Interface(i)))
        {
            this_type -> ResetInterfaces(); // Remove all the interfaces if a loop is detected. The error will be reported later
            this_type -> MarkCircular();
            ReportSemError(SemanticError::CIRCULAR_INTERFACE,
                           interface_declaration -> identifier_token,
                           interface_declaration -> ExtendsInterface(interface_declaration -> NumExtendsInterfaces() - 1) -> RightToken(),
                           this_type -> ContainingPackage() -> PackageName(),
                           this_type -> ExternalName());
            break;
        }
    }

    this_type -> MarkHeaderProcessed();

    state_stack.Pop();

    return;
}


//
// Marked type and all other types that are nested inside it "circular"
//
void Semantic::MarkCircularNest(TypeSymbol *type)
{
    if (type -> Circular())
        return;

    //
    // Mark the type as circular
    //
    type -> MarkCircular();
    type -> super = control.Object();
    type -> ResetInterfaces();

    //
    // Recursively, process any nested type...
    //
    AstClassDeclaration *class_declaration = type -> declaration -> ClassDeclarationCast();
    if (class_declaration)
    {
        AstClassBody *class_body = class_declaration -> class_body;
        for (int i = 0; i < class_body -> NumNestedClasses(); i++)
            MarkCircularNest(class_body -> NestedClass(i) -> semantic_environment -> Type());
        for (int k = 0; k < class_body -> NumNestedInterfaces(); k++)
            MarkCircularNest(class_body -> NestedInterface(k) -> semantic_environment -> Type());
    }
    else
    {
        AstInterfaceDeclaration *interface_declaration = (AstInterfaceDeclaration *) type -> declaration;
        for (int i = 0; i < interface_declaration -> NumNestedClasses(); i++)
            MarkCircularNest(interface_declaration -> NestedClass(i) -> semantic_environment -> Type());
        for (int k = 0; k < interface_declaration -> NumNestedInterfaces(); k++)
            MarkCircularNest(interface_declaration -> NestedInterface(k) -> semantic_environment -> Type());
    }

    return;
}


//
// Compute the set of super types associated with this outer-level type
// and check for circularity.
//
void Semantic::ProcessSuperTypesOfOuterType(TypeSymbol *type)
{
assert((! type -> IsNested()) || type -> owner -> MethodCast());
    if (type -> super)
    {
        type -> supertypes_closure -> AddElement(type -> super -> outermost_type);
        type -> supertypes_closure -> Union(*type -> super -> outermost_type -> supertypes_closure);
    }

    for (int k = 0; k < type -> NumInterfaces(); k++)
    {
        type -> supertypes_closure -> AddElement(type -> Interface(k) -> outermost_type);
        type -> supertypes_closure -> Union(*type -> Interface(k) -> outermost_type -> supertypes_closure);
    }

    SymbolSet &inner_types = *(type -> innertypes_closure);
    for (TypeSymbol *inner_type = (TypeSymbol *) inner_types.FirstElement();
                     inner_type;
                     inner_type = (TypeSymbol *) inner_types.NextElement())
    {
        TypeSymbol *super_type = inner_type -> super;
        for (int k = 0; super_type;
                        super_type = (TypeSymbol *) (k < inner_type -> NumInterfaces() ? inner_type -> Interface(k++) : NULL))
        {
            if (super_type -> outermost_type != type)
            {
                type -> supertypes_closure -> AddElement(super_type -> outermost_type);
                type -> supertypes_closure -> Union(*super_type -> outermost_type -> supertypes_closure);
            }
        }
    }

    bool circular = type -> supertypes_closure -> IsElement(type) ||
                    type -> subtypes_closure -> Intersects(*type -> supertypes_closure);
    if (circular)
    {
        if (type -> Circular())        // If the type is already marked circular, an error message has already been issued
            type -> MarkNonCircular(); // Remove the circular mark, so that we can remark the whole "nest" ?
        else
        {
            if (type -> ACC_INTERFACE())
            {
                AstInterfaceDeclaration *interface_declaration = (AstInterfaceDeclaration *) type -> declaration;
                int right_token_index = interface_declaration -> NumExtendsInterfaces() - 1;

                ReportSemError(SemanticError::CIRCULAR_INTERFACE,
                               interface_declaration -> identifier_token,
                               (interface_declaration -> NumExtendsInterfaces() > 0
                                                       ? interface_declaration -> ExtendsInterface(right_token_index) -> RightToken()
                                                       : interface_declaration -> identifier_token),
                               type -> ContainingPackage() -> PackageName(),
                               type -> ExternalName());
            }
            else
            {
                AstClassDeclaration *class_declaration = (AstClassDeclaration *) type -> declaration;
                int right_token_index = class_declaration -> NumInterfaces() - 1;

                ReportSemError(SemanticError::CIRCULAR_CLASS,
                               class_declaration -> identifier_token,
                               (class_declaration -> NumInterfaces() > 0
                                                   ? class_declaration -> Interface(right_token_index) -> RightToken()
                                                   : (class_declaration -> super_opt
                                                                         ? class_declaration -> super_opt -> RightToken()
                                                                         : class_declaration -> identifier_token)),
                               type -> ContainingPackage() -> PackageName(),
                               type -> ExternalName());

                SetObjectSuperType(type, class_declaration -> identifier_token);
assert(type -> Identity() != control.object_name_symbol || type -> ContainingPackage() != control.system_package);
            }
        }

        MarkCircularNest(type);
    }

    return;
}


//
// The array partially_ordered_types contains a list of inner types. For
// each of these types, compute the set of super types associated with it
// and check for circularity.
//
void Semantic::ProcessSuperTypesOfInnerType(TypeSymbol *type, Tuple<TypeSymbol *> &partially_ordered_types)
{
    for (int l = 0; l < partially_ordered_types.Length(); l++)
    {
        TypeSymbol *inner_type = partially_ordered_types[l];

        SymbolSet &nested_types = *(inner_type -> innertypes_closure);
        nested_types.AddElement(inner_type); // Compute reflexive transitive closure
        for (TypeSymbol *nested_type = (TypeSymbol *) nested_types.FirstElement();
                         nested_type;
                         nested_type = (TypeSymbol *) nested_types.NextElement())
        {
            TypeSymbol *super_type = nested_type -> super;
            for (int k = 0; super_type;
                            super_type = (TypeSymbol *) (k < nested_type -> NumInterfaces() ? nested_type -> Interface(k++) : NULL))
            {
                for ( ; super_type; super_type = super_type -> owner -> TypeCast())
                {
                    if (type -> innertypes_closure -> IsElement(super_type))
                        break;
                }

                if (super_type && super_type != inner_type)
                {
                    inner_type -> supertypes_closure -> AddElement(super_type);
                    inner_type -> supertypes_closure -> Union(*super_type -> supertypes_closure);
                }
            }
        }

        bool circular = inner_type -> supertypes_closure -> IsElement(inner_type) ||
                        inner_type -> subtypes_closure -> Intersects(*inner_type -> supertypes_closure);

        if (circular)
        {
            MarkCircularNest(inner_type);

            if (inner_type -> ACC_INTERFACE())
            {
                AstInterfaceDeclaration *interface_declaration = (AstInterfaceDeclaration *) inner_type -> declaration;
                ReportSemError(SemanticError::CIRCULAR_INTERFACE,
                               interface_declaration -> identifier_token,
                               (interface_declaration -> NumExtendsInterfaces() > 0
                                                       ? interface_declaration -> ExtendsInterface(interface_declaration -> NumExtendsInterfaces() - 1) -> RightToken()
                                                       : interface_declaration -> identifier_token),
                               inner_type -> ContainingPackage() -> PackageName(),
                               inner_type -> ExternalName());
            }
            else
            {
                AstClassDeclaration *class_declaration = (AstClassDeclaration *) inner_type -> declaration;
                ReportSemError(SemanticError::CIRCULAR_CLASS,
                               class_declaration -> identifier_token,
                               (class_declaration -> NumInterfaces() > 0
                                                   ? class_declaration -> Interface(class_declaration -> NumInterfaces() - 1) -> RightToken()
                                                   : (class_declaration -> super_opt
                                                                         ? class_declaration -> super_opt -> RightToken()
                                                                         : class_declaration -> identifier_token)),
                               inner_type -> ContainingPackage() -> PackageName(),
                               inner_type -> ExternalName());
            }
        }
    }

    //
    // At this point the innertypes_closure set contains only the
    // immediate inner types.
    //
    if (partially_ordered_types.Length() > 1) // inner_types set has more than one element?
    {
        SymbolSet &inner_types = *(type -> innertypes_closure);
assert(partially_ordered_types.Length() == inner_types.Size());
        TopologicalSort *topological_sorter = new TopologicalSort(inner_types, partially_ordered_types);
        topological_sorter -> Sort();
        delete topological_sorter;
    }

    //
    // Now, complete the closure set of inner types.
    //
    for (int i = 0; i < partially_ordered_types.Length(); i++)
    {
        TypeSymbol *inner_type = partially_ordered_types[i];
        type -> AddNestedType(inner_type);
        type -> innertypes_closure -> Union(*(inner_type -> innertypes_closure));
    }

    return;
}


void Semantic::ProcessTypeHeaders(AstClassDeclaration *class_declaration)
{
    ProcessTypeHeader(class_declaration);
    ProcessNestedTypeHeaders(class_declaration -> semantic_environment -> Type(), class_declaration -> class_body);
    ProcessSuperTypesOfOuterType(class_declaration -> semantic_environment -> Type());

    return;
}


void Semantic::ProcessTypeHeaders(AstInterfaceDeclaration *interface_declaration)
{
    ProcessTypeHeader(interface_declaration);
    ProcessNestedTypeHeaders(interface_declaration);
    ProcessSuperTypesOfOuterType(interface_declaration -> semantic_environment -> Type());

    return;
}


void Semantic::ReportTypeInaccessible(LexStream::TokenIndex left_tok, LexStream::TokenIndex right_tok, TypeSymbol *type)
{
    ReportSemError(SemanticError::TYPE_NOT_ACCESSIBLE,
                   left_tok,
                   right_tok,
                   type -> ContainingPackage() -> PackageName(),
                   type -> ExternalName(),
                   (type -> ACC_PRIVATE() ? StringConstant::US_private : (type -> ACC_PROTECTED() ? StringConstant::US_protected : StringConstant::US_default)));

    return;
}


TypeSymbol *Semantic::FindNestedType(TypeSymbol *type, LexStream::TokenIndex identifier_token)
{
    if (type == control.null_type || type == control.no_type || type -> Primitive())
        return NULL;

    NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(identifier_token);

    if (! type -> expanded_type_table)
        ComputeTypesClosure(type, identifier_token);
    TypeShadowSymbol *type_shadow_symbol = type -> expanded_type_table -> FindTypeShadowSymbol(name_symbol);

    return (type_shadow_symbol ? FindTypeInShadow(type_shadow_symbol, identifier_token)
                               : type -> FindTypeSymbol(name_symbol));
}


TypeSymbol *Semantic::MustFindNestedType(TypeSymbol *type, Ast *name)
{
    AstSimpleName *simple_name = name -> SimpleNameCast();
    LexStream::TokenIndex identifier_token = (simple_name ? simple_name -> identifier_token
                                                          : ((AstFieldAccess *) name) -> identifier_token);

    TypeSymbol *inner_type = FindNestedType(type, identifier_token);
    if (inner_type)
         TypeAccessCheck(name, inner_type);
    else inner_type = GetBadNestedType(type, identifier_token);

    return inner_type;
}


//
// The Ast name is a qualified name (simple name or a field access). The function FindTypeInLayer
// searches for the first subname that is the name of a type contained in the set inner_types.
// If such a type is found, it is returned. Otherwise, the whole qualified name is resolved to
// a symbol that is returned. 
//
TypeSymbol *Semantic::FindTypeInLayer(Ast *name, SymbolSet &inner_types)
{
    //
    // Unwind all the field accesses until we get to a base that is a simple name
    //
    Tuple<AstFieldAccess *> field;
    for (AstFieldAccess *field_access = name -> FieldAccessCast(); field_access; field_access = field_access -> base -> FieldAccessCast())
    {
        field.Next() = field_access;
        name = field_access -> base;
    }

    //
    // If the simple_name base is a type that is an element in the inner_types set
    // return it. Otherwise, assume it is a package name...
    //
    AstSimpleName *simple_name = name -> SimpleNameCast();
assert(simple_name);
    PackageSymbol *package = NULL;
    TypeSymbol *type = FindType(simple_name -> identifier_token);
    if (type)
    {
        if (inner_types.IsElement(type))
            return type;
    }
    else // If the simple_name is not a type, assume it is a package
    {
        NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(simple_name -> identifier_token);
        package = control.external_table.FindPackageSymbol(name_symbol);
        if (! package)
            package = control.external_table.InsertPackageSymbol(name_symbol, NULL);
        control.FindPathsToDirectory(package);
    }

    //
    // We now go through the field access in order until we either encouter a type that is an element of inner_types,
    // in which case, we return the type. Otherwise, we return NULL.
    //
    //
    for (int i = field.Length() - 1; i >= 0; i--)
    {
        AstFieldAccess *field_access = field[i];

        if (type) // The base name is a type that is not contained in the inner_types set?
        {
            type = FindNestedType(type, field_access -> identifier_token); // resolve the next type...
            if (! type)
                break;
            if (inner_types.IsElement(type))
                return type;
        }
        else 
        {
            NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token);
            type = package -> FindTypeSymbol(name_symbol);
            if (! type)
            {
                FileSymbol *file_symbol = Control::GetFile(package, name_symbol, control.option.depend);
                if (file_symbol)
                    type = ReadType(file_symbol, package, name_symbol, field_access -> identifier_token);
            }
            else if (type -> SourcePending())
                 control.ProcessHeaders(type -> file_symbol);

            //            
            //            
            //
            if (type)
            {
                if (inner_types.IsElement(type))
                    return type;
            }
            else // If the field access was not resolved to a type assume it is a package
            {
                NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token);
                PackageSymbol *subpackage = package -> FindPackageSymbol(name_symbol);
                if (! subpackage)
                    subpackage = package -> InsertPackageSymbol(name_symbol);
                control.FindPathsToDirectory(subpackage);
                package = subpackage;
            }
        }
    }

    return NULL;
}


void Semantic::ProcessNestedSuperTypes(TypeSymbol *type)
{
    int num_inner_types = type -> innertypes_closure -> Size();

    if (num_inner_types > 0)
    {
        SymbolSet &inner_types = *(type -> innertypes_closure);

        for (TypeSymbol *inner_type = (TypeSymbol *) inner_types.FirstElement();
                         inner_type;
                         inner_type = (TypeSymbol *) inner_types.NextElement())
        {
            if (inner_type -> ACC_INTERFACE())
            {
                AstInterfaceDeclaration *inner_interface_declaration = (AstInterfaceDeclaration *) inner_type -> declaration;
 
                for (int l = 0; l < inner_interface_declaration -> NumExtendsInterfaces(); l++)
                {
                    AstExpression *interface_name = inner_interface_declaration -> ExtendsInterface(l);
                    TypeSymbol *super_type = FindTypeInLayer(interface_name, inner_types);
                    if (super_type)
                        super_type -> subtypes -> AddElement(inner_type);
                }
            }
            else
            {
                AstClassDeclaration *inner_class_declaration = (AstClassDeclaration *) inner_type -> declaration;

                if (inner_class_declaration -> super_opt)
                {
                    TypeSymbol *super_type = FindTypeInLayer(inner_class_declaration -> super_opt, inner_types);
                    if (super_type)
                        super_type -> subtypes -> AddElement(inner_type);
                }

                for (int l = 0; l < inner_class_declaration -> NumInterfaces(); l++)
                {
                    TypeSymbol *super_type = FindTypeInLayer(inner_class_declaration -> Interface(l), inner_types);
                    if (super_type)
                        super_type -> subtypes -> AddElement(inner_type);
                }
            }
        }

        //
        // Create a partial order or the inner types. If there are cycles,
        // then the order is arbitrary.
        //
        Tuple<TypeSymbol *> partially_ordered_types;

        if (num_inner_types > 0) // inner_types set is not empty?
        {
            TypeCycleChecker *cycle_checker = new TypeCycleChecker(partially_ordered_types);
            cycle_checker -> PartialOrder(inner_types);
            delete cycle_checker;
        }

        for (int k = 0; k < partially_ordered_types.Length(); k++)
        {
            TypeSymbol *inner_type = partially_ordered_types[k];
            if (inner_type -> ACC_INTERFACE())
            {
                AstInterfaceDeclaration *inner_interface_declaration = (AstInterfaceDeclaration *) inner_type -> declaration;
                ProcessTypeHeader(inner_interface_declaration);
                ProcessNestedTypeHeaders(inner_interface_declaration);
            }
            else
            {
                AstClassDeclaration *inner_class_declaration = (AstClassDeclaration *) inner_type -> declaration;
                ProcessTypeHeader(inner_class_declaration);
                ProcessNestedTypeHeaders(inner_class_declaration -> semantic_environment -> Type(),
                                        inner_class_declaration -> class_body);
            }
        }

        ProcessSuperTypesOfInnerType(type, partially_ordered_types);
    }

    return;
}


void Semantic::ProcessNestedTypeHeaders(TypeSymbol *type, AstClassBody *class_body)
{
    if (type -> expanded_type_table && (type -> super != control.Object() || type -> NumInterfaces() > 0))
    {
        delete type -> expanded_type_table;
        type  -> expanded_type_table = NULL;
    }

    if (! type -> expanded_type_table)
        ComputeTypesClosure(type, class_body -> left_brace_token);

    state_stack.Push(type -> semantic_environment);

    type -> innertypes_closure = new SymbolSet;

    for (int i = 0; i < class_body -> NumNestedClasses(); i++)
    {
        if (class_body -> NestedClass(i) -> semantic_environment)
            type -> innertypes_closure -> AddElement(class_body -> NestedClass(i) -> semantic_environment -> Type());
    }

    for (int j = 0; j < class_body -> NumNestedInterfaces(); j++)
    {
        if (class_body -> NestedInterface(j) -> semantic_environment)
            type -> innertypes_closure -> AddElement(class_body -> NestedInterface(j) -> semantic_environment -> Type());
    }

    ProcessNestedSuperTypes(type);

    state_stack.Pop();

    return;
}


void Semantic::ProcessNestedTypeHeaders(AstInterfaceDeclaration *interface_declaration)
{
    TypeSymbol *type = interface_declaration -> semantic_environment -> Type();
    if (type -> expanded_type_table && type -> NumInterfaces() > 0)
    {
        delete type -> expanded_type_table;
        type  -> expanded_type_table = NULL;
    }

    if (! type -> expanded_type_table)
        ComputeTypesClosure(type, interface_declaration -> identifier_token);

    state_stack.Push(interface_declaration -> semantic_environment);

    type -> innertypes_closure = new SymbolSet;

    for (int i = 0; i < interface_declaration -> NumNestedClasses(); i++)
    {
        if (interface_declaration -> NestedClass(i) -> semantic_environment)
            type -> innertypes_closure -> AddElement(interface_declaration -> NestedClass(i) -> semantic_environment -> Type());
    }

    for (int j = 0; j < interface_declaration -> NumNestedInterfaces(); j++)
    {
        if (interface_declaration -> NestedInterface(j) -> semantic_environment)
            type -> innertypes_closure -> AddElement(interface_declaration -> NestedInterface(j) -> semantic_environment -> Type());
    }

    ProcessNestedSuperTypes(type);

    state_stack.Pop();

    return;
}


//
// Pass 3: Process all method and constructor declarations within the compilation unit so that
//         any field initialization enclosed in the compilation unit can invoke any constructor or
//         method within the unit.
//
inline void Semantic::ProcessConstructorMembers(AstClassBody *class_body)
{
    TypeSymbol *this_type = ThisType();
assert(this_type -> HeaderProcessed());

    //
    // If the class contains no constructor, ...
    //
    if (class_body -> NumConstructors() > 0)
    {
        for (int k = 0; k < class_body -> NumConstructors(); k++)
            ProcessConstructorDeclaration(class_body -> Constructor(k));
    }
    else if (! this_type -> Anonymous())
         AddDefaultConstructor(this_type);

    this_type -> MarkConstructorMembersProcessed();

    return;
}


inline void Semantic::ProcessMethodMembers(AstClassBody *class_body)
{
assert(ThisType() -> HeaderProcessed());
    for (int k = 0; k < class_body -> NumMethods(); k++)
        ProcessMethodDeclaration(class_body -> Method(k));

    ThisType() -> MarkMethodMembersProcessed();

    return;
}


inline void Semantic::ProcessFieldMembers(AstClassBody *class_body)
{
assert(ThisType() -> HeaderProcessed());

    for (int i = 0; i < class_body -> NumInstanceVariables(); i++)
        ProcessFieldDeclaration(class_body -> InstanceVariable(i));

    for (int k = 0; k < class_body -> NumClassVariables(); k++)
        ProcessFieldDeclaration(class_body -> ClassVariable(k));

    ThisType() -> MarkFieldMembersProcessed();

    return;
}


void Semantic::ProcessMembers(SemanticEnvironment *environment, AstClassBody *class_body)
{
    //
    //
    //
    state_stack.Push(environment);
    TypeSymbol *this_type = ThisType();
assert(! this_type -> ConstructorMembersProcessed() || this_type -> Bad());
assert(! this_type -> MethodMembersProcessed() || this_type -> Bad());
assert(! this_type -> FieldMembersProcessed() || this_type -> Bad());

    ProcessConstructorMembers(class_body);
    ProcessMethodMembers(class_body);
    ProcessFieldMembers(class_body);

    delete this_type -> innertypes_closure; // save some space !!!
    this_type -> innertypes_closure = NULL;

    if (! this_type -> IsTopLevel())
    {
        for (int i = 0; i < class_body -> NumStaticInitializers(); i++)
        {
             ReportSemError(SemanticError::STATIC_INITIALIZER_IN_INNER_CLASS,
                            class_body -> StaticInitializer(i) -> LeftToken(),
                            class_body -> StaticInitializer(i) -> RightToken(),
                            this_type -> Name(),
                            this_type -> FileLoc());
        }
    }

    for (int i = 0; i < this_type -> NumNestedTypes(); i++)
    {
        TypeSymbol *inner_type = this_type -> NestedType(i);

        if (inner_type -> ACC_INTERFACE())
        {
            AstInterfaceDeclaration *interface_declaration = (AstInterfaceDeclaration *) inner_type -> declaration;

            ProcessMembers(interface_declaration);

            if (! this_type -> IsTopLevel())
            {
                //
                // TODO: 1.1 assumption
                //
                // As every field in an interface is static, we presume that all interfaces
                // should be treated as static entities
                //
                if (interface_declaration -> semantic_environment)
                {
                    ReportSemError(SemanticError::STATIC_TYPE_IN_INNER_CLASS,
                                   interface_declaration -> identifier_token,
                                   interface_declaration -> identifier_token,
                                   lex_stream -> Name(interface_declaration -> identifier_token),
                                   this_type -> Name(),
                                   this_type -> FileLoc());
                }
            }
        }
        else
        {
            AstClassDeclaration *class_declaration = (AstClassDeclaration *) inner_type -> declaration;

            ProcessMembers(class_declaration -> semantic_environment, class_declaration -> class_body);

            if (! this_type -> IsTopLevel())
            {
                if (class_declaration -> semantic_environment && class_declaration -> semantic_environment -> Type() -> ACC_STATIC())
                {
                    ReportSemError(SemanticError::STATIC_TYPE_IN_INNER_CLASS,
                                   class_declaration -> identifier_token,
                                   class_declaration -> identifier_token,
                                   lex_stream -> Name(class_declaration -> identifier_token),
                                   this_type -> Name(),
                                   this_type -> FileLoc());
                }
            }
        }
    }

    state_stack.Pop();

    return;
}


inline void Semantic::ProcessMethodMembers(AstInterfaceDeclaration *interface_declaration)
{
assert(ThisType() -> HeaderProcessed());

    for (int k = 0; k < interface_declaration -> NumMethods(); k++)
        ProcessMethodDeclaration(interface_declaration -> Method(k));

    ThisType() -> MarkMethodMembersProcessed();

    return;
}


inline void Semantic::ProcessFieldMembers(AstInterfaceDeclaration *interface_declaration)
{
assert(ThisType() -> HeaderProcessed());

    for (int k = 0; k < interface_declaration -> NumClassVariables(); k++)
        ProcessFieldDeclaration(interface_declaration -> ClassVariable(k));

    ThisType() -> MarkFieldMembersProcessed();

    return;
}


void Semantic::ProcessMembers(AstInterfaceDeclaration *interface_declaration)
{
    //
    //
    //
    state_stack.Push(interface_declaration -> semantic_environment);
    TypeSymbol *this_type = ThisType();

assert(! this_type -> MethodMembersProcessed() || this_type -> Bad());
assert(! this_type -> FieldMembersProcessed() || this_type -> Bad());

    ProcessMethodMembers(interface_declaration);
    ProcessFieldMembers(interface_declaration);

    delete this_type -> innertypes_closure; // save some space !!!
    this_type -> innertypes_closure = NULL;

    for (int i = 0; i < this_type -> NumNestedTypes(); i++)
    {
        TypeSymbol *inner_type = this_type -> NestedType(i);

        if (inner_type -> ACC_INTERFACE())
        {
            AstInterfaceDeclaration *interface_declaration = (AstInterfaceDeclaration *) inner_type -> declaration;
            ProcessMembers(interface_declaration);
        }
        else
        {
            AstClassDeclaration *class_declaration = (AstClassDeclaration *) inner_type -> declaration;
            ProcessMembers(class_declaration -> semantic_environment, class_declaration -> class_body);
        }
    }

    state_stack.Pop();

    return;
}


//
// Pass 4: Process the field declarations at the top level of the types
//
void Semantic::CompleteSymbolTable(SemanticEnvironment *environment, LexStream::TokenIndex identifier_token, AstClassBody *class_body)
{
    if (compilation_unit -> BadCompilationUnitCast())
        return;

    state_stack.Push(environment);
    TypeSymbol *this_type = ThisType();
assert(this_type -> ConstructorMembersProcessed());
assert(this_type -> MethodMembersProcessed());
assert(this_type -> FieldMembersProcessed());

    //
    //
    //
    if (! this_type -> expanded_method_table)
        ComputeMethodsClosure(this_type, identifier_token);

    ExpandedMethodTable &expanded_table = *(this_type -> expanded_method_table);
    if (! this_type -> ACC_ABSTRACT())
    {
        //
        // Check that every abstract method that is inherited is overridden.
        //
        for (int i = 0; i < expanded_table.symbol_pool.Length(); i++)
        {
            MethodSymbol *method = expanded_table.symbol_pool[i] -> method_symbol;

            if (method -> ACC_ABSTRACT())
            {
                TypeSymbol *containing_type = method -> containing_type;
                if (containing_type != this_type)
                {
                    //
                    // If the method is contained in an abstract method read from a class file,
                    // then it is possible that the abstract method is just out-of-date and needs
                    // to be recompiled.
                    //
                    ReportSemError((! containing_type -> ACC_INTERFACE()) &&
                                   (containing_type -> file_symbol && containing_type -> file_symbol -> IsClass())
                                        ? SemanticError::NON_ABSTRACT_TYPE_INHERITS_ABSTRACT_METHOD_FROM_ABSTRACT_CLASS
                                        : SemanticError::NON_ABSTRACT_TYPE_INHERITS_ABSTRACT_METHOD,
                                   identifier_token,
                                   identifier_token,
                                   method -> Header((Semantic *) this, identifier_token),
                                   containing_type -> ContainingPackage() -> PackageName(),
                                   containing_type -> ExternalName(),
                                   this_type -> ContainingPackage() -> PackageName(),
                                   this_type -> ExternalName());
                }
            }
        }

        //
        // If the super class of this_type is abstract and it is contained in a
        // different package, check to see if its members include abstract methods
        // with default access. If so, we must issue error messages for them also
        // as they cannot be overridden.
        //
        if (this_type != control.Object() && this_type -> super -> ACC_ABSTRACT() &&
            (this_type -> ContainingPackage() != this_type -> super -> ContainingPackage()))
        {
            ExpandedMethodTable &super_expanded_table = *(this_type -> super -> expanded_method_table);
            for (int i = 0; i < super_expanded_table.symbol_pool.Length(); i++)
            {
                MethodSymbol *method = super_expanded_table.symbol_pool[i] -> method_symbol;

                if (method -> ACC_ABSTRACT() &&
                    (! (method -> ACC_PUBLIC() || method -> ACC_PROTECTED() || method -> ACC_PRIVATE())))
                {
                    TypeSymbol *containing_type = method -> containing_type;

                    //
                    // If the method is contained in an abstract type read from a class file,
                    // then it is possible that the abstract method is just out-of-date and needs
                    // to be recompiled.
                    //
                    ReportSemError(SemanticError::NON_ABSTRACT_TYPE_CANNOT_OVERRIDE_DEFAULT_ABSTRACT_METHOD,
                                   identifier_token,
                                   identifier_token,
                                   method -> Header((Semantic *) this, identifier_token),
                                   containing_type -> ContainingPackage() -> PackageName(),
                                   containing_type -> ExternalName(),
                                   this_type -> ContainingPackage() -> PackageName(),
                                   this_type -> ExternalName());
                }
            }
        }
    }

    for (int i = 0; i < expanded_table.symbol_pool.Length(); i++)
    {
        MethodShadowSymbol *method_shadow = expanded_table.symbol_pool[i];

        if (method_shadow -> NumConflicts() > 0)
        {
            MethodSymbol *method = method_shadow -> method_symbol;

            if (method -> containing_type == this_type)
            {
                AstMethodDeclaration *method_declaration = (AstMethodDeclaration *) method -> method_or_constructor_declaration;

                for (int k = 0; k < method_shadow -> NumConflicts(); k++)
                {
                    MethodSymbol *hidden_method = method_shadow -> Conflict(k);
                    if (method -> containing_type != hidden_method -> containing_type) // the methods are not in the same type
                        CheckMethodOverride(method_declaration, hidden_method);
                }
            }
            else
            {
                AstClassDeclaration *class_declaration = (AstClassDeclaration *) this_type -> declaration;

                for (int k = 0; k < method_shadow -> NumConflicts(); k++)
                {
                    MethodSymbol *hidden_method = method_shadow -> Conflict(k);
                    if (method -> containing_type != hidden_method -> containing_type) // the methods are not in the same type
                        CheckMethodOverride(class_declaration, method, hidden_method);
                }

                if (! method -> ACC_ABSTRACT())
                {
                    if (method -> ACC_STATIC())
                    {
                        ReportSemError(SemanticError::STATIC_OVERRIDE_ABSTRACT_EXTERNALLY,
                                       class_declaration -> identifier_token,
                                       (class_declaration -> NumInterfaces() > 0
                                             ? class_declaration -> Interface(class_declaration -> NumInterfaces() - 1) -> RightToken()
                                             : (class_declaration -> super_opt ? class_declaration -> super_opt -> RightToken()
                                                                               : class_declaration -> identifier_token)),
                                       lex_stream -> Name(class_declaration -> identifier_token),
                                       method -> Header((Semantic *) this, identifier_token),
                                       method -> containing_type -> ContainingPackage() -> PackageName(),
                                       method -> containing_type -> ExternalName(),
                                       method_shadow -> Conflict(0) -> Header((Semantic *) this, identifier_token),
                                       method_shadow -> Conflict(0) -> containing_type -> ContainingPackage() -> PackageName(),
                                       method_shadow -> Conflict(0) -> containing_type -> ExternalName());
                    }
                }
            }

            method_shadow -> RemoveConflicts();
        }
    }

    ProcessStaticInitializers(class_body);

    ProcessBlockInitializers(class_body);

    //
    // Reset the this_variable and this_method may have been set in
    // ProcessStaticInitializers and/or ProcessBlockInitializers.
    // Indicate that there is no method being currently compiled
    // in this environment.
    //
    ThisVariable() = NULL;
    ThisMethod() = NULL;

    //
    // Recursively process all inner types
    //
    for (int l = 0; l < this_type -> NumNestedTypes(); l++)
    {
        TypeSymbol *inner_type = this_type -> NestedType(l);
        if (inner_type -> ACC_INTERFACE())
            CompleteSymbolTable((AstInterfaceDeclaration *) inner_type -> declaration);
        else
        {
            AstClassDeclaration *class_declaration = (AstClassDeclaration *) inner_type -> declaration;
            CompleteSymbolTable(class_declaration -> semantic_environment,
                                class_declaration -> identifier_token, class_declaration -> class_body);
        }
    }

    state_stack.Pop();

    return;
}


void Semantic::CompleteSymbolTable(AstInterfaceDeclaration *interface_declaration)
{
    if (compilation_unit -> BadCompilationUnitCast())
        return;

    state_stack.Push(interface_declaration -> semantic_environment);
    TypeSymbol *this_type = ThisType();
assert(this_type -> MethodMembersProcessed());
assert(this_type -> FieldMembersProcessed());

    //
    //
    //
    if (! this_type -> expanded_method_table)
        ComputeMethodsClosure(this_type, interface_declaration -> identifier_token);

    ExpandedMethodTable &expanded_table = *(this_type -> expanded_method_table);
    for (int i = 0; i < interface_declaration -> NumMethods(); i++)
    {
        AstMethodDeclaration *method_declaration = interface_declaration -> Method(i);
        MethodSymbol *method = method_declaration -> method_symbol;

        if (method)
        {
            MethodShadowSymbol *method_shadow = expanded_table.FindOverloadMethodShadow(method,
                                                                                        (Semantic *) this,
                                                                                        interface_declaration -> identifier_token);
            for (int k = 0; k < method_shadow -> NumConflicts(); k++)
            {
                if (method_shadow -> method_symbol -> Type() != method_shadow -> Conflict(k) -> Type())
                {
                    LexStream::TokenIndex token_location = method_declaration -> method_declarator -> identifier_token;

                    ReportSemError(SemanticError::MISMATCHED_INHERITED_METHOD,
                                   method_declaration -> method_declarator -> LeftToken(),
                                   method_declaration -> method_declarator -> RightToken(),
                                   method_shadow -> method_symbol -> Header((Semantic *) this, token_location),
                                   method_shadow -> Conflict(k) -> Header((Semantic *) this, token_location),
                                   method_shadow -> Conflict(k) -> containing_type -> ContainingPackage() -> PackageName(),
                                   method_shadow -> Conflict(k) -> containing_type -> ExternalName());
                }

                if (method_shadow -> method_symbol -> containing_type == this_type) // override ?
                    CheckInheritedMethodThrows(method_declaration, method_shadow -> Conflict(k));
            }
        }
    }

    //
    // Compute the set of final variables (all fields in an interface are final) in this type.
    //
    Tuple<VariableSymbol *> finals(this_type -> NumVariableSymbols());
    for (int j = 0; j < this_type -> NumVariableSymbols(); j++)
    {
        VariableSymbol *variable_symbol = this_type -> VariableSym(j);
        finals.Next() = variable_symbol;
    }

    //
    // Initialize each variable, in turn
    //
    for (int k = 0; k < interface_declaration -> NumClassVariables(); k++)
        InitializeVariable(interface_declaration -> ClassVariable(k), finals);

    //
    // Recursively process all inner types
    //
    for (int l = 0; l < this_type -> NumNestedTypes(); l++)
    {
        TypeSymbol *inner_type = this_type -> NestedType(l);
        if (inner_type -> ACC_INTERFACE())
            CompleteSymbolTable((AstInterfaceDeclaration *) inner_type -> declaration);
        else
        {
            AstClassDeclaration *class_declaration = (AstClassDeclaration *) inner_type -> declaration;
            CompleteSymbolTable(class_declaration -> semantic_environment,
                                class_declaration -> identifier_token, class_declaration -> class_body);
        }
    }

    state_stack.Pop();

    return;
}


//
// Pass 5: Free up unneeded space.
//
void Semantic::CleanUp()
{
    for (int i = 0; i < compilation_unit -> NumTypeDeclarations(); i++)
    {
        TypeSymbol *type = NULL;
        Ast *type_declaration = compilation_unit -> TypeDeclaration(i);
        switch(type_declaration -> kind)
        {
            case Ast::CLASS:
            {
                AstClassDeclaration *class_declaration = (AstClassDeclaration *) type_declaration;
                if (class_declaration -> semantic_environment)
                    type = class_declaration -> semantic_environment -> Type();
                break;
            }
            case Ast::INTERFACE:
            {
                AstInterfaceDeclaration *interface_declaration = (AstInterfaceDeclaration *) type_declaration;
                if (interface_declaration -> semantic_environment)
                    type = interface_declaration -> semantic_environment -> Type();
                break;
            }
        }

        if (type)
            CleanUpType(type);
    }

    return;
}


void Semantic::CleanUpType(TypeSymbol *type)
{
    type -> DeleteAnonymousTypes();
    for (int i = 0; i < type -> NumNestedTypes(); i++)
        CleanUpType(type -> NestedType(i));

    type -> CompressSpace(); // space optimization

    for (int j = 0; j < type -> NumMethodSymbols(); j++)
        type -> MethodSym(j) -> CleanUp();

    delete type -> local;
    type -> local = NULL;

    delete type -> non_local;
    type -> non_local = NULL;

    delete type -> semantic_environment;
    type -> semantic_environment = NULL;

    type -> declaration = NULL;

    return;
}


//
//
//
void Semantic::ConvertUtf8ToUnicode(wchar_t *target, char *source, int len)
{
    for (int i = 0; i < len; i++, target++)
    {
        u1 ch = source[i];

        if ((ch & 0x80) == 0)
            *target = ch;
        else if ((ch & 0xE0) == 0xC0)
        {
            *target = ch & 0x1F;
            *target <<= 6;
            i++;
            ch = source[i] & 0x3F;
            *target += ch;
        }
        else if ((ch & 0xF0) == 0xE0)
        {
            *target = ch & 0x0F;
            *target <<= 6;
            i++;
            ch = source[i] & 0x3F;
            *target += ch;

            *target <<= 6;
            i++;
            ch = source[i] & 0x3F;
            *target += ch;
        }
        else
        {
cerr << "chaos: Damn, Caramba, Zut !!!\n";
        }
    }

    *target = U_NULL;
    return;
}


TypeSymbol *Semantic::ReadType(FileSymbol *file_symbol, PackageSymbol *package, NameSymbol *name_symbol, LexStream::TokenIndex tok)
{
    TypeSymbol *type;

    if (file_symbol && file_symbol -> IsJava())
    {
        if (! file_symbol -> semantic)
            control.ProcessHeaders(file_symbol);
        type = package -> FindTypeSymbol(name_symbol);
        if (! type)
        {
            type = package -> InsertOuterTypeSymbol(name_symbol);
            type -> outermost_type = type;
            type -> supertypes_closure = new SymbolSet;
            type -> subtypes = new SymbolSet;
            type -> semantic_environment = new SemanticEnvironment((Semantic *) this, type, NULL);
            if (type != control.Object())
                type -> super = (type == control.Throwable() ? control.Object() : control.Throwable());
            type -> SetOwner(package);
            type -> SetSignature(control);
            type -> MarkBad();
            AddDefaultConstructor(type);
            type -> file_symbol = file_symbol;
            file_symbol -> types.Next() = type;

            ReportSemError(SemanticError::TYPE_NOT_FOUND,
                           tok,
                           tok,
                           type -> ContainingPackage() -> PackageName(),
                           type -> ExternalName());
        }
    }
    else // Read class file.
    {
        type = package -> InsertOuterTypeSymbol(name_symbol);
        type -> outermost_type = type;
        type -> supertypes_closure = new SymbolSet;
        type -> subtypes = new SymbolSet;
        type -> SetOwner(package);
        type -> SetSignature(control);

        if (file_symbol)
        {
            type -> file_symbol = file_symbol;
            type -> SetLocation();

            file_symbol -> package = package;
            file_symbol -> types.Next() = type;

            ReadClassFile(type, tok);

assert (! type -> IsNested());
            control.input_class_file_set.AddElement(file_symbol);
        }
        else
        {
            control.ProcessBadType(type);
            if (type != control.Object())
                type -> super = (type == control.Throwable() ? control.Object() : control.Throwable());
            type -> MarkBad();
            AddDefaultConstructor(type);

            ReportSemError(SemanticError::TYPE_NOT_FOUND,
                           tok,
                           tok,
                           type -> ContainingPackage() -> PackageName(),
                           type -> ExternalName());

            if (package == control.unnamed_package)
            {
                TypeSymbol *old_type = (TypeSymbol *) control.unnamed_package_types.Image(type -> Identity());
                if (! old_type)
                    control.unnamed_package_types.AddElement(type);
                else
                {
                    ReportSemError(SemanticError::DUPLICATE_TYPE_DECLARATION,
                                   tok,
                                   tok,
                                   type -> Name(),
                                   old_type -> FileLoc());
                }
            }
        }
    }

    return type;
}


TypeSymbol *Semantic::GetBadNestedType(TypeSymbol *type, LexStream::TokenIndex identifier_token)
{
    NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(identifier_token);

    TypeSymbol *outermost_type = type -> outermost_type;
    if (! outermost_type -> non_local)
        outermost_type -> non_local = new SymbolSet;
    if (! outermost_type -> local)
        outermost_type -> local = new SymbolSet;

    int length = type -> ExternalNameLength() + 1 + name_symbol -> NameLength(); // +1 for $,... +1 for $
    wchar_t *external_name = new wchar_t[length + 1]; // +1 for '\0';
    wcscpy(external_name, type -> ExternalName());
    wcscat(external_name, StringConstant::US__DS_);
    wcscat(external_name, name_symbol -> Name());

    TypeSymbol *inner_type = type -> InsertNestedTypeSymbol(name_symbol);
    inner_type -> outermost_type = type -> outermost_type;
    inner_type -> supertypes_closure = new SymbolSet;
    inner_type -> subtypes = new SymbolSet;
    inner_type -> SetExternalIdentity(control.FindOrInsertName(external_name, length));
    inner_type -> semantic_environment = new SemanticEnvironment((Semantic *) this,
                                                                 inner_type,
                                                                 type -> semantic_environment);
    inner_type -> super = control.Object();
    inner_type -> SetOwner(type);
    inner_type -> SetSignature(control);
    inner_type -> InsertThis(0);
    inner_type -> MarkBad();
    AddDefaultConstructor(inner_type);

    ReportSemError(SemanticError::TYPE_NOT_FOUND,
                   identifier_token,
                   identifier_token,
                   inner_type -> ContainingPackage() -> PackageName(),
                   inner_type -> ExternalName());

    delete [] external_name;

    return inner_type;
}


Symbol *Semantic::ProcessImportQualifiedName(AstExpression *name)
{
    PackageSymbol *package = NULL;
    TypeSymbol *type = NULL;

    AstFieldAccess *field_access = name -> FieldAccessCast();
    if (field_access)
    {
        Symbol *symbol = ProcessImportQualifiedName(field_access -> base);

        type = symbol -> TypeCast();
        if (type) // The base name is a type
        {
            if (! type -> NestedTypesProcessed())
                type -> ProcessNestedTypeSignatures((Semantic *) this, field_access -> identifier_token);
            NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token);
            TypeSymbol *inner_type = type -> FindTypeSymbol(name_symbol);
            if (! inner_type)
                 inner_type = GetBadNestedType(type, field_access -> identifier_token);
            else if (! (inner_type -> ACC_PUBLIC() || inner_type -> ContainingPackage() == this_package))
                 ReportTypeInaccessible(field_access, inner_type);
            type = inner_type;
            field_access -> symbol = type; // save the type to which this expression was resolved for later use...
        }
        else 
        {
            package = symbol -> PackageCast();
            NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token);
            type = package -> FindTypeSymbol(name_symbol);
            if (! type)
            {
                FileSymbol *file_symbol = Control::GetFile(package, name_symbol, control.option.depend);
                if (file_symbol)
                    type = ReadType(file_symbol, package, name_symbol, field_access -> identifier_token);
            }
            else if (type -> SourcePending())
                 control.ProcessHeaders(type -> file_symbol);

            //
            // If the field_access was resolved to a type, save it later use.
            // Otherwise, assume the field_access is a package name.
            //
            if (type)
                 field_access -> symbol = type;
            else
            {
                NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token);
                PackageSymbol *subpackage = package -> FindPackageSymbol(name_symbol);
                if (! subpackage)
                    subpackage = package -> InsertPackageSymbol(name_symbol);
                control.FindPathsToDirectory(subpackage);
                package = subpackage;
            }
        }
    }
    else
    {
        AstSimpleName *simple_name = name -> SimpleNameCast();
assert(simple_name);

        //
        // From the 1.1 document:
        //
        //    Nested classes of all sorts (top-level or inner) can be imported by either kind of
        //    import statement. Class names in import statements must be fully package
        //    qualified, and be resolvable without reference to inheritance relations...
        //
        if (compilation_unit -> package_declaration_opt)
        {
            type = FindSimpleNameType(this_package, simple_name -> identifier_token);
            //
            // If the type was not found, look for it in the unnamed package.
            // The relevant passages that justify this lookup are:
            // 6.5.4.11, 6.7, 7.4.2, 7.5.1
            //
            if (! type)
                type = FindSimpleNameType(control.unnamed_package, simple_name -> identifier_token);
        }
        else type = FindSimpleNameType(control.unnamed_package, simple_name -> identifier_token);

        //
        // If the simple_name is a type, save it. Otherwise, assume it is a package
        //
        if (type)
        {
            if (! (type -> ACC_PUBLIC() || type -> ContainingPackage() == this_package))
                ReportTypeInaccessible(name, type);
            simple_name -> symbol = type;
        }
        else
        {
            NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(simple_name -> identifier_token);
            package = control.external_table.FindPackageSymbol(name_symbol);
            if (! package)
                package = control.external_table.InsertPackageSymbol(name_symbol, NULL);
            control.FindPathsToDirectory(package);
        }
    }

    return (type ? (Symbol *) type : (Symbol *) package);
}


Symbol *Semantic::ProcessPackageOrType(AstExpression *name)
{
    PackageSymbol *package = NULL;
    TypeSymbol *type = NULL;

    AstFieldAccess *field_access = name -> FieldAccessCast();
    if (field_access)
    {
        Symbol *symbol = ProcessPackageOrType(field_access -> base);

        type = symbol -> TypeCast();
        if (type) // The base name is a type
        {
            type = MustFindNestedType(type, field_access);
            field_access -> symbol = type; // save the type to which this expression was resolved for later use...
        }
        else 
        {
            package = symbol -> PackageCast();
            NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token);
            type = package -> FindTypeSymbol(name_symbol);
            if (! type)
            {
                FileSymbol *file_symbol = Control::GetFile(package, name_symbol, control.option.depend);
                if (file_symbol)
                    type = ReadType(file_symbol, package, name_symbol, field_access -> identifier_token);
            }
            else if (type -> SourcePending())
                 control.ProcessHeaders(type -> file_symbol);

            //
            // If the field access was resolved into a type, then save it.
            // Otherwise, assume it is a package
            //
            if (type)
                 field_access -> symbol = type; // save the type to which this expression was resolved for later use...
            else
            {
                NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token);
                PackageSymbol *subpackage = package -> FindPackageSymbol(name_symbol);
                if (! subpackage)
                    subpackage = package -> InsertPackageSymbol(name_symbol);
                control.FindPathsToDirectory(subpackage);
                package = subpackage;
            }
        }
    }
    else
    {
        AstSimpleName *simple_name = name -> SimpleNameCast();
assert(simple_name);
        type = FindType(simple_name -> identifier_token);
        if (type)
        {
            TypeAccessCheck(simple_name, type);
            simple_name -> symbol = type;
        }
        else
        {
            NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(simple_name -> identifier_token);
            package = control.external_table.FindPackageSymbol(name_symbol);
            if (! package)
                package = control.external_table.InsertPackageSymbol(name_symbol, NULL);
            control.FindPathsToDirectory(package);
        }
    }

    return (type ? (Symbol *) type : (Symbol *) package);
}


void Semantic::ProcessTypeImportOnDemandDeclaration(AstImportDeclaration *import_declaration)
{
    Symbol *symbol = ProcessImportQualifiedName(import_declaration -> name);

    PackageSymbol *package = symbol -> PackageCast();
    if (package && package -> directory.Length() == 0)
    {
        ReportSemError(SemanticError::PACKAGE_NOT_FOUND,
                       import_declaration -> name -> LeftToken(),
                       import_declaration -> name -> RightToken(),
                       package -> PackageName());
    }

    //
    // Two or more type-import-on-demand may name the same package; the effect is as if there
    // were only one such declaration.
    //
    for (int i = 0; i < import_on_demand_packages.Length(); i++)
    {
        if (symbol == import_on_demand_packages[i])
            return;
    }

    import_on_demand_packages.Next() = symbol;

    return;
}


//
// The Ast name is a name expression (either a qualified name or a simplename)
// FindFirstType traverses the name tree and returns the first subtree that it
// finds that matches a type. As a side-effect, each subtree that matches a package
// or a type has that package or type recorded in its "symbol" field.
//
AstExpression *Semantic::FindFirstType(Ast *name)
{
    AstExpression *name_expression = NULL;

    AstFieldAccess *field_access = name -> FieldAccessCast();
    if (field_access)
    {
        AstExpression *expr = FindFirstType(field_access -> base);

        if (expr -> symbol -> TypeCast()) // A subexpression has been found, pass it up
            name_expression = expr;
        else
        {
            PackageSymbol *package = expr -> symbol -> PackageCast();
assert(package);
            name_expression = field_access; // The relevant subexpression might be this field access...

            NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token);
            TypeSymbol *type = package -> FindTypeSymbol(name_symbol);
            if (type)
            {
                if (type -> SourcePending())
                    control.ProcessHeaders(type -> file_symbol);
                field_access -> symbol = type;
            }
            else
            {
                FileSymbol *file_symbol = Control::GetFile(package, name_symbol, control.option.depend);
                if (file_symbol)
                    field_access -> symbol = ReadType(file_symbol, package, name_symbol, field_access -> identifier_token);
                else
                {
                    PackageSymbol *subpackage = package -> FindPackageSymbol(name_symbol);
                    if (! subpackage)
                        subpackage = package -> InsertPackageSymbol(name_symbol);
                    control.FindPathsToDirectory(subpackage);
                    field_access -> symbol = subpackage;
                }
            }
        }
    }
    else
    {
        AstSimpleName *simple_name = name -> SimpleNameCast();
assert(simple_name);
        simple_name -> symbol = ProcessPackageOrType(simple_name);
        name_expression = simple_name;
    }

    return name_expression;
}


TypeSymbol *Semantic::FindSimpleNameType(PackageSymbol *package, LexStream::TokenIndex identifier_token)
{
    NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(identifier_token);
    TypeSymbol *type = package -> FindTypeSymbol(name_symbol);
    if (type)
    {
        if (type -> SourcePending())
             control.ProcessHeaders(type -> file_symbol);
    }
    else
    {
        //
        // Check whether or not the type was declared in another compilation unit
        // in the main package.
        //
        FileSymbol *file_symbol = Control::GetFile(package, name_symbol, control.option.depend);
        if (file_symbol)
            type = ReadType(file_symbol, package, name_symbol, identifier_token);
    }

    return type;
}

void Semantic::ProcessSingleTypeImportDeclaration(AstImportDeclaration *import_declaration)
{
    Symbol *symbol = ProcessImportQualifiedName(import_declaration -> name);
     *package = symbol -> PackageCast();
    if (package)
    {
        ReportSemError(SemanticError::UNKNOWN_QUALIFIED_NAME_BASE,
                       import_declaration -> name -> LeftToken(),
                       import_declaration -> name -> RightToken(),
                       package -> PackageName());
        return;
    }

    TypeSymbol *type = symbol -> TypeCast();

    //
    // If two single-type-import declarations in the same compilation unit attempt to
    // import types with the same simple name, then a compile-time error occurs, unless
    // the two types are the same type, in which case the duplicate declaration is ignored.
    //
    for (int i = 0; i < single_type_imports.Length(); i++)
    {
        if (type == single_type_imports[i])
            return;
    }

    TypeSymbol *old_type;
    int k;
    for (k = 0; k < compilation_unit -> NumTypeDeclarations(); k++)
    {
        AstClassDeclaration *class_declaration;
        AstInterfaceDeclaration *interface_declaration;

        if (class_declaration = compilation_unit -> TypeDeclaration(k) -> ClassDeclarationCast())
        {
            if (class_declaration -> semantic_environment)
            {
                old_type = class_declaration -> semantic_environment -> Type();
                if (old_type -> Identity() == type -> Identity())
                    break;
            }
        }
        else if (interface_declaration = compilation_unit -> TypeDeclaration(k) -> InterfaceDeclarationCast())
        {
            if (interface_declaration -> semantic_environment)
            {
                old_type = interface_declaration -> semantic_environment -> Type();
                if (old_type -> Identity() == type -> Identity())
                    break;
            }
        }
    }

    if (k < compilation_unit -> NumTypeDeclarations())
    {
        ReportSemError(SemanticError::DUPLICATE_TYPE_DECLARATION,
                       import_declaration -> name -> LeftToken(),
                       import_declaration -> name -> RightToken(),
                       lex_stream -> Name(import_declaration -> name -> RightToken()),
                       old_type -> FileLoc());
    }
    else
    {
        int i = 0;
        for (i = 0; i < compilation_unit -> NumImportDeclarations(); i++)
        {
            TypeSymbol *other_type = compilation_unit -> ImportDeclaration(i) -> name -> Type();
            if ((compilation_unit -> ImportDeclaration(i) == import_declaration) ||
                (other_type && other_type -> Identity() == type -> Identity()))
                break;
        }

assert(i < compilation_unit -> NumImportDeclarations());
        if (compilation_unit -> ImportDeclaration(i) == import_declaration) // No duplicate found
        {
            import_declaration -> name -> symbol = type;
            single_type_imports.Next() = type;
        }
        else
        {
            FileLocation file_location(lex_stream, compilation_unit -> ImportDeclaration(i) -> LeftToken());
            ReportSemError(SemanticError::DUPLICATE_TYPE_DECLARATION,
                           import_declaration -> name -> LeftToken(),
                           import_declaration -> name -> RightToken(),
                           lex_stream -> Name(import_declaration -> name -> RightToken()),
                           file_location.location);
        }
    }

    if (! (type -> ACC_PUBLIC() || type -> ContainingPackage() == this_package))
        ReportTypeInaccessible(import_declaration -> name, type);

    return;
}


void Semantic::ProcessFieldDeclaration(AstFieldDeclaration *field_declaration)
{
    TypeSymbol *this_type = ThisType();
    AccessFlags access_flags = (this_type -> ACC_INTERFACE()
                                           ? ProcessConstantModifiers(field_declaration)
                                           : ProcessFieldModifiers(field_declaration));

    //
    // New feature in java 1.2 that is undocumented in the 1.1 document.
    // A field may be declared static iff it is final and not blank-final...
    //
    if (access_flags.ACC_STATIC() && (! access_flags.ACC_FINAL()) && this_type -> IsInner())
    {
        AstModifier *modifier = NULL;
        for (int i = 0; i < field_declaration -> NumVariableModifiers(); i++)
        {
            if (field_declaration -> VariableModifier(i) -> kind == Ast::STATIC)
                modifier = field_declaration -> VariableModifier(i);
        }

assert(modifier);
        ReportSemError(SemanticError::STATIC_FIELD_IN_INNER_CLASS,
                       modifier -> modifier_kind_token,
                       modifier -> modifier_kind_token);
    }

    //
    //
    //
    AstArrayType *array_type = field_declaration -> type -> ArrayTypeCast();
    Ast *actual_type = (array_type ? array_type -> type : field_declaration -> type);
    AstPrimitiveType *primitive_type = actual_type -> PrimitiveTypeCast();
    TypeSymbol *field_type = (primitive_type ? FindPrimitiveType(primitive_type) : MustFindType(actual_type));
    for (int i = 0; i < field_declaration -> NumVariableDeclarators(); i++)
    {
        AstVariableDeclarator *variable_declarator = field_declaration -> VariableDeclarator(i);
        AstVariableDeclaratorId *name = variable_declarator -> variable_declarator_name;
        NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(name -> identifier_token);
 
        if (this_type -> FindVariableSymbol(name_symbol))
        {
            ReportSemError(SemanticError::DUPLICATE_FIELD,
                           name -> identifier_token,
                           name -> identifier_token,
                           name_symbol -> Name(),
                           this_type -> Name());
        }
        else
        {
            VariableSymbol *variable = this_type -> InsertVariableSymbol(name_symbol);
            int num_dimensions = (array_type ? array_type -> NumBrackets() : 0) + name -> NumBrackets();
            if (num_dimensions == 0)
                 variable -> SetType(field_type);
            else variable -> SetType(field_type -> GetArrayType((Semantic *) this, num_dimensions));
            variable -> SetFlags(access_flags);
            variable -> SetOwner(this_type);
            variable -> declarator = variable_declarator;
            variable -> MarkIncomplete(); // the declaration of a field is not complete until its initializer
                                          // (if any) has been processed.
            variable_declarator -> symbol = variable;
        }
    }

    return;
}


void Semantic::GenerateLocalConstructor(MethodSymbol *constructor)
{
    TypeSymbol *local_type = constructor -> containing_type;

    //
    // Make up external name for constructor
    //
    wchar_t info[12],
            *str = &info[11];
    *str = U_NULL;
    int num = local_type -> NumGeneratedConstructors();
    do
    {
        *--str = (U_0 + num % 10);
        num /= 10;
    } while (num != 0);

    int length = 12 + (&info[11] - str); // +12 for constructor$
    wchar_t *external_name = new wchar_t[length + 1]; // +1 for '\0';
    wcscpy(external_name, StringConstant::US__constructor_DOLLAR);
    wcscat(external_name, str);
    constructor -> SetExternalIdentity(control.FindOrInsertName(external_name, length)); // Turn the constructor into a method

    delete [] external_name;

    //
    // Make generated constructor symbol. The associated symbol table will not contain too many elements.
    //
    BlockSymbol *block_symbol = new BlockSymbol(local_type -> NumConstructorParameters() +
                                                constructor -> NumFormalParameters() + 3);
    block_symbol -> max_variable_index = 1; // All types need a spot for "this"

    MethodSymbol *local_constructor = local_type -> LocalConstructorOverload(constructor);
    local_constructor -> method_or_constructor_declaration = constructor -> method_or_constructor_declaration;
    local_constructor -> SetType(control.void_type);
    local_constructor -> SetContainingType(local_type);
    local_constructor -> SetBlockSymbol(block_symbol);
    ((AccessFlags *) local_constructor) -> access_flags = ((AccessFlags *) constructor) -> access_flags;
    for (int i = 0; i < constructor -> NumThrows(); i++)
        local_constructor -> AddThrows(constructor -> Throws(i));

    for (int j = 0; j < local_type -> NumConstructorParameters(); j++)
    {
        VariableSymbol *param = local_type -> ConstructorParameter(j),
                       *symbol = block_symbol -> InsertVariableSymbol(param -> Identity());
        symbol -> SetType(param -> Type());
        symbol -> SetOwner(local_constructor);
        symbol -> SetExternalIdentity(param -> ExternalIdentity());
        symbol -> SetLocalVariableIndex(block_symbol -> max_variable_index++);
        if (symbol -> Type() == control.long_type || symbol -> Type() == control.double_type)
            block_symbol -> max_variable_index++;
        local_constructor -> AddFormalParameter(symbol);
    }

    //
    // Add all the parameters from the original constructor to the symbol
    // table of the local constructor. However, only mark them complete and
    // do not yet assign a number to them. This will be done after we know
    // how many extra "local" variable shadows are needed.
    //
    for (int k = 0; k < constructor -> NumFormalParameters(); k++)
    {
        VariableSymbol *param = constructor -> FormalParameter(k),
                       *symbol = block_symbol -> InsertVariableSymbol(param -> Identity());
        symbol -> SetType(param -> Type());
        symbol -> SetOwner(local_constructor);
        symbol -> MarkComplete();
    }

    local_type -> AddGeneratedConstructor(local_constructor);

    return;
}


void Semantic::ProcessConstructorDeclaration(AstConstructorDeclaration *constructor_declaration)
{
    TypeSymbol *this_type = ThisType();
    if (this_type -> Anonymous())
    {
        ReportSemError(SemanticError::CONSTRUCTOR_FOUND_IN_ANONYMOUS_CLASS,
                       constructor_declaration -> LeftToken(),
                       constructor_declaration -> RightToken());
        return;
    }

    AccessFlags access_flags = ProcessConstructorModifiers(constructor_declaration);

    AstMethodDeclarator *constructor_declarator = constructor_declaration -> constructor_declarator;
    NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(constructor_declarator -> identifier_token);
    wchar_t *constructor_name = lex_stream -> Name(constructor_declarator -> identifier_token);

    if (lex_stream -> NameSymbol(constructor_declarator -> identifier_token) != this_type -> Identity())
    {
        ReportSemError(SemanticError::MISMATCHED_CONSTRUCTOR_NAME,
                       constructor_declarator -> identifier_token,
                       constructor_declarator -> identifier_token,
                       constructor_name,
                       this_type -> Name());
        constructor_name = this_type -> Name(); // assume the proper name !
    }

    //
    // As the body of the constructor may not have been parsed yet, we estimate a size
    // for its symbol table based on the number of lines in the body + a margin for one-liners.
    //
    AstConstructorBlock *block = constructor_declaration -> constructor_body -> ConstructorBlockCast();
    BlockSymbol *block_symbol = new BlockSymbol(constructor_declarator -> NumFormalParameters() + 3);
    block_symbol -> max_variable_index = 1; // All types need a spot for "this".

    ProcessFormalParameters(block_symbol, constructor_declarator);

    //
    // Note that constructors are always named "<init>"
    //
    MethodSymbol *constructor = this_type -> FindMethodSymbol(control.init_name_symbol);

    if (! constructor) // there exists a constructor already in type -> table.
         constructor = this_type -> InsertConstructorSymbol(control.init_name_symbol);
    else
    {
        if (this_type -> FindOverloadMethod(constructor, constructor_declarator))
        {
            ReportSemError(SemanticError::DUPLICATE_CONSTRUCTOR,
                           constructor_declarator -> LeftToken(),
                           constructor_declarator -> RightToken(),
                           this_type -> Name());
            delete block_symbol;
            return;
        }

        constructor = this_type -> Overload(constructor);
    }

    //
    // If the method is not static, leave a slot for the "this" pointer.
    //
    constructor -> SetType(control.void_type);
    constructor -> SetFlags(access_flags);
    constructor -> SetContainingType(this_type);
    constructor -> SetBlockSymbol(block_symbol);
    constructor -> method_or_constructor_declaration = constructor_declaration;

    VariableSymbol *this0_variable = NULL;
    if (this_type -> IsInner())
    {
        this0_variable = block_symbol -> InsertVariableSymbol(control.this0_name_symbol);
        this0_variable -> SetType(this_type -> ContainingType());
        this0_variable -> SetOwner(constructor);
        this0_variable -> SetLocalVariableIndex(block_symbol -> max_variable_index++);
    }

    for (int i = 0; i < constructor_declarator -> NumFormalParameters(); i++)
    {
        AstFormalParameter *parameter = constructor_declarator -> FormalParameter(i);
        VariableSymbol *symbol = parameter -> parameter_symbol;

        symbol -> SetOwner(constructor);
        symbol -> SetLocalVariableIndex(block_symbol -> max_variable_index++);
        if (symbol -> Type() == control.long_type || symbol -> Type() == control.double_type)
            block_symbol -> max_variable_index++;
        symbol -> declarator = parameter -> variable_declarator_name;
        constructor -> AddFormalParameter(symbol);
    }

    constructor -> SetSignature(control, this0_variable);

    for (int k = 0; k < constructor_declaration -> NumThrows(); k++)
    {
        AstExpression *throw_expression = constructor_declaration -> Throw(k);
        TypeSymbol *throw_type = MustFindType(throw_expression);
        throw_expression -> symbol = throw_type;
        constructor -> AddThrows(throw_type);
    }

    constructor_declaration -> constructor_symbol = constructor; // save for processing bodies later.

    if (this_type -> IsLocal())
        GenerateLocalConstructor(constructor);

    return;
}


void Semantic::AddDefaultConstructor(TypeSymbol *type)
{
    MethodSymbol *constructor = type -> InsertConstructorSymbol(control.init_name_symbol);

    BlockSymbol *block_symbol = new BlockSymbol(1); // TODO: make sure this size is right !!!
    block_symbol -> max_variable_index = 1; // All types need a spot for "this"

    constructor -> SetType(control.void_type);
    constructor -> SetContainingType(type);
    constructor -> SetBlockSymbol(block_symbol);
    if (type -> ACC_PUBLIC())
        constructor -> SetACC_PUBLIC();

    VariableSymbol *this0_variable = NULL;
    if (type -> IsInner())
    {
        this0_variable = block_symbol -> InsertVariableSymbol(control.this0_name_symbol);
        this0_variable -> SetType(type -> ContainingType());
        this0_variable -> SetOwner(constructor);
        this0_variable -> SetLocalVariableIndex(block_symbol -> max_variable_index++);
    }

    constructor -> SetSignature(control, this0_variable);

    AstClassDeclaration *class_declaration = (type -> declaration ? type -> declaration -> ClassDeclarationCast()
                                                                  : (AstClassDeclaration *) NULL);
    if (class_declaration)
    {
        AstClassBody *class_body = class_declaration -> class_body;
        LexStream::TokenIndex left_loc  = class_declaration -> identifier_token,
                              right_loc = (class_declaration -> super_opt ? class_declaration -> super_opt -> RightToken()
                                                                          : class_declaration -> identifier_token);

        AstMethodDeclarator *method_declarator       = compilation_unit -> ast_pool -> GenMethodDeclarator();
        method_declarator -> identifier_token        = left_loc;
        method_declarator -> left_parenthesis_token  = left_loc;
        method_declarator -> right_parenthesis_token = right_loc;

        AstSuperCall *super_call = NULL;
        if (type != control.Object())
        {
            super_call                            = compilation_unit -> ast_pool -> GenSuperCall();
            super_call -> base_opt                = NULL;
            super_call -> dot_token_opt           = left_loc;
            super_call -> super_token             = left_loc;
            super_call -> left_parenthesis_token  = left_loc;
            super_call -> right_parenthesis_token = right_loc;
            super_call -> semicolon_token         = right_loc;
        }

        AstReturnStatement *return_statement = compilation_unit -> ast_pool -> GenReturnStatement();
        return_statement -> return_token = left_loc;
        return_statement -> expression_opt = NULL;
        return_statement -> semicolon_token = left_loc;
        return_statement -> is_reachable = true;

        AstBlock *block = compilation_unit -> ast_pool -> GenBlock();
        block -> AllocateBlockStatements(1); // this block contains one statement
        block -> left_brace_token  = left_loc;
        block -> right_brace_token = right_loc;

        block -> is_reachable = true;
        block -> can_complete_normally = false;
        block -> AddStatement(return_statement);

        AstConstructorBlock *constructor_block                   = compilation_unit -> ast_pool -> GenConstructorBlock();
        constructor_block -> left_brace_token                    = left_loc;
        constructor_block -> explicit_constructor_invocation_opt = super_call;
        constructor_block -> block                               = block;
        constructor_block -> right_brace_token                   = right_loc;

        AstConstructorDeclaration *constructor_declaration = compilation_unit -> ast_pool -> GenConstructorDeclaration();
        constructor_declaration -> constructor_declarator   = method_declarator;
        constructor_declaration -> constructor_body         = constructor_block;

        constructor_declaration -> constructor_symbol = constructor;
        constructor -> method_or_constructor_declaration = constructor_declaration;
        class_body -> default_constructor = constructor_declaration;

        if (type -> IsLocal())
            GenerateLocalConstructor(constructor);
    }

    return;
}


void Semantic::CheckInheritedMethodThrows(AstMethodDeclaration *method_declaration, MethodSymbol *method)
{
    for (int i = 0; i < method_declaration -> NumThrows(); i++)
    {
        AstExpression *name = method_declaration -> Throw(i);
        TypeSymbol *exception = (TypeSymbol *) name -> symbol;

        if (CheckedException(exception))
        {
            int k;
            for (k = method -> NumThrows((Semantic *) this, name -> RightToken()) - 1; k >= 0; k--)
            {
                if (exception -> IsSubclass(method -> Throws(k)))
                    break;
            }

            if (k < 0)
            {
                ReportSemError(SemanticError::MISMATCHED_OVERRIDDEN_EXCEPTION,
                               name -> LeftToken(),
                               name -> RightToken(),
                               exception -> Name(),
                               method -> Header((Semantic *) this, name -> RightToken()),
                               method -> containing_type -> ContainingPackage() -> PackageName(),
                               method -> containing_type -> ExternalName());
            }
        }
    }

    return;
}


void Semantic::CheckMethodOverride(AstMethodDeclaration *method_declaration, MethodSymbol *hidden_method)
{
    AstMethodDeclarator *method_declarator = method_declaration -> method_declarator;
    MethodSymbol *method = method_declaration -> method_symbol;
    LexStream::TokenIndex token_location = method_declaration -> method_declarator -> identifier_token;

    if (hidden_method -> Type() != method -> Type())
        ReportSemError(SemanticError::MISMATCHED_INHERITED_METHOD,
                       method_declarator -> LeftToken(),
                       method_declarator -> RightToken(),
                       method -> Header((Semantic *) this, token_location),
                       hidden_method -> Header((Semantic *) this, token_location),
                       hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                       hidden_method -> containing_type -> ExternalName());
    if (hidden_method -> IsFinal() || hidden_method -> ACC_PRIVATE()) // Merged because same kind of message. See error.cpp
        ReportSemError(hidden_method -> IsFinal() ? SemanticError::FINAL_METHOD_OVERRIDE : SemanticError::PRIVATE_METHOD_OVERRIDE,
                       method_declarator -> LeftToken(),
                       method_declarator -> RightToken(),
                       method -> Header((Semantic *) this, token_location),
                       hidden_method -> Header((Semantic *) this, token_location),
                       hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                       hidden_method -> containing_type -> ExternalName());

    if (method -> ACC_STATIC() != hidden_method -> ACC_STATIC())
    {
        if (method -> ACC_STATIC())
             ReportSemError(SemanticError::INSTANCE_METHOD_OVERRIDE,
                            method_declarator -> LeftToken(),
                            method_declarator -> RightToken(),
                            method -> Header((Semantic *) this, token_location),
                            hidden_method -> Header((Semantic *) this, token_location),
                            hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                            hidden_method -> containing_type -> ExternalName());
        else ReportSemError(SemanticError::CLASS_METHOD_OVERRIDE,
                            method_declarator -> LeftToken(),
                            method_declarator -> RightToken(),
                            method -> Header((Semantic *) this, token_location),
                            hidden_method -> Header((Semantic *) this, token_location),
                            hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                            hidden_method -> containing_type -> ExternalName());
    }

    if (hidden_method -> ACC_PUBLIC())
    {
        if (! method -> ACC_PUBLIC())
            ReportSemError(SemanticError::BAD_ACCESS_METHOD_OVERRIDE,
                           method_declarator -> LeftToken(),
                           method_declarator -> RightToken(),
                           method -> Header((Semantic *) this, token_location),
                           (method -> ACC_PRIVATE() ? StringConstant::US_private : (method -> ACC_PROTECTED() ? StringConstant::US_protected : StringConstant::US_default)),
                           hidden_method -> Header((Semantic *) this, token_location),
                           StringConstant::US_public,
                           hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                           hidden_method -> containing_type -> ExternalName());
    }
    else if (hidden_method -> ACC_PROTECTED())
    {
        if (! (method -> ACC_PROTECTED() || method -> ACC_PUBLIC()))
             ReportSemError(SemanticError::BAD_ACCESS_METHOD_OVERRIDE,
                            method_declarator -> LeftToken(),
                            method_declarator -> RightToken(),
                            method -> Header((Semantic *) this, token_location),
                            StringConstant::US_default,
                            hidden_method -> Header((Semantic *) this, token_location),
                            StringConstant::US_protected,
                            hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                            hidden_method -> containing_type -> ExternalName());
    }
    else if (method -> ACC_PRIVATE()) // The hidden_method method must have default access as it cannot be private...
    {
         ReportSemError(SemanticError::BAD_ACCESS_METHOD_OVERRIDE,
                        method_declarator -> LeftToken(),
                        method_declarator -> RightToken(),
                        method -> Header((Semantic *) this, token_location),
                        StringConstant::US_private,
                        hidden_method -> Header((Semantic *) this, token_location),
                        StringConstant::US_default,
                        hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                        hidden_method -> containing_type -> ExternalName());
    }

    CheckInheritedMethodThrows(method_declaration, hidden_method);

    return;
}


void Semantic::CheckInheritedMethodThrows(AstClassDeclaration *class_declaration, MethodSymbol *method, MethodSymbol *hidden_method)
{
    for (int i = method -> NumThrows((Semantic *) this, class_declaration -> identifier_token) - 1; i >= 0; i--)
    {
        TypeSymbol *exception = method -> Throws(i);

        if (CheckedException(exception))
        {
            int k;
            for (k = hidden_method -> NumThrows((Semantic *) this, class_declaration -> identifier_token) - 1; k >= 0; k--)
            {
                if (exception -> IsSubclass(hidden_method -> Throws(k)))
                    break;
            }

            if (k < 0)
            {
                ReportSemError(SemanticError::MISMATCHED_OVERRIDDEN_EXCEPTION_EXTERNALLY,
                               class_declaration -> identifier_token,
                               (class_declaration -> NumInterfaces() > 0
                                     ? class_declaration -> Interface(class_declaration -> NumInterfaces() - 1) -> RightToken()
                                     : (class_declaration -> super_opt ? class_declaration -> super_opt -> RightToken()
                                                                       : class_declaration -> identifier_token)),
                               lex_stream -> Name(class_declaration -> identifier_token),
                               exception -> Name(),
                               method -> Header((Semantic *) this, class_declaration -> identifier_token),
                               hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                               hidden_method -> containing_type -> ExternalName(),
                               hidden_method -> Header((Semantic *) this, class_declaration -> identifier_token),
                               method -> containing_type -> ContainingPackage() -> PackageName(),
                               method -> containing_type -> ExternalName());
            }
        }
    }

    return;
}


void Semantic::CheckMethodOverride(AstClassDeclaration *class_declaration, MethodSymbol *method, MethodSymbol *hidden_method)
{
    if (hidden_method -> Type() != method -> Type())
        ReportSemError(SemanticError::MISMATCHED_INHERITED_METHOD_EXTERNALLY,
                       class_declaration -> identifier_token,
                       (class_declaration -> NumInterfaces() > 0
                                           ? class_declaration -> Interface(class_declaration -> NumInterfaces() - 1) -> RightToken()
                                           : (class_declaration -> super_opt ? class_declaration -> super_opt -> RightToken()
                                                                             : class_declaration -> identifier_token)),
                       lex_stream -> Name(class_declaration -> identifier_token),
                       method -> Header((Semantic *) this, class_declaration -> identifier_token),
                       method -> containing_type -> ContainingPackage() -> PackageName(),
                       method -> containing_type -> ExternalName(),
                       hidden_method -> Header((Semantic *) this, class_declaration -> identifier_token),
                       hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                       hidden_method -> containing_type -> ExternalName());
    if (hidden_method -> IsFinal() || hidden_method -> ACC_PRIVATE()) // Merged because same kind of message. See error.cpp
        ReportSemError(hidden_method -> IsFinal() ? SemanticError::FINAL_METHOD_OVERRIDE_EXTERNALLY
                                                  : SemanticError::PRIVATE_METHOD_OVERRIDE_EXTERNALLY,
                       class_declaration -> identifier_token,
                       (class_declaration -> NumInterfaces() > 0
                                           ? class_declaration -> Interface(class_declaration -> NumInterfaces() - 1) -> RightToken()
                                           : (class_declaration -> super_opt ? class_declaration -> super_opt -> RightToken()
                                                                             : class_declaration -> identifier_token)),
                       lex_stream -> Name(class_declaration -> identifier_token),
                       method -> Header((Semantic *) this, class_declaration -> identifier_token),
                       method -> containing_type -> ContainingPackage() -> PackageName(),
                       method -> containing_type -> ExternalName(),
                       hidden_method -> Header((Semantic *) this, class_declaration -> identifier_token),
                       hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                       hidden_method -> containing_type -> ExternalName());

    if (method -> ACC_STATIC() != hidden_method -> ACC_STATIC())
    {
        if (method -> ACC_STATIC())
             ReportSemError(SemanticError::INSTANCE_METHOD_OVERRIDE_EXTERNALLY,
                            class_declaration -> identifier_token,
                            (class_declaration -> NumInterfaces() > 0
                                                ? class_declaration -> Interface(class_declaration -> NumInterfaces() - 1) -> RightToken()
                                                : (class_declaration -> super_opt ? class_declaration -> super_opt -> RightToken()
                                                                                  : class_declaration -> identifier_token)),
                            lex_stream -> Name(class_declaration -> identifier_token),
                            method -> Header((Semantic *) this, class_declaration -> identifier_token),
                            method -> containing_type -> ContainingPackage() -> PackageName(),
                            method -> containing_type -> ExternalName(),
                            hidden_method -> Header((Semantic *) this, class_declaration -> identifier_token),
                            hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                            hidden_method -> containing_type -> ExternalName());
        else ReportSemError(SemanticError::CLASS_METHOD_OVERRIDE_EXTERNALLY,
                            class_declaration -> identifier_token,
                            (class_declaration -> NumInterfaces() > 0
                                                ? class_declaration -> Interface(class_declaration -> NumInterfaces() - 1) -> RightToken()
                                                : (class_declaration -> super_opt ? class_declaration -> super_opt -> RightToken()
                                                                                  : class_declaration -> identifier_token)),
                            lex_stream -> Name(class_declaration -> identifier_token),
                            method -> Header((Semantic *) this, class_declaration -> identifier_token),
                            method -> containing_type -> ContainingPackage() -> PackageName(),
                            method -> containing_type -> ExternalName(),
                            hidden_method -> Header((Semantic *) this, class_declaration -> identifier_token),
                            hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                            hidden_method -> containing_type -> ExternalName());
    }

    if (hidden_method -> ACC_PUBLIC())
    {
        if (! method -> ACC_PUBLIC())
            ReportSemError(SemanticError::BAD_ACCESS_METHOD_OVERRIDE_EXTERNALLY,
                           class_declaration -> identifier_token,
                           (class_declaration -> NumInterfaces() > 0
                                               ? class_declaration -> Interface(class_declaration -> NumInterfaces() - 1) -> RightToken()
                                               : (class_declaration -> super_opt ? class_declaration -> super_opt -> RightToken()
                                                                                 : class_declaration -> identifier_token)),
                           lex_stream -> Name(class_declaration -> identifier_token),
                           method -> Header((Semantic *) this, class_declaration -> identifier_token),
                           (method -> ACC_PRIVATE() ? StringConstant::US_private
                                                    : (method -> ACC_PROTECTED() ? StringConstant::US_protected
                                                                                 : StringConstant::US_default)),
                           method -> containing_type -> ContainingPackage() -> PackageName(),
                           method -> containing_type -> ExternalName(),
                           hidden_method -> Header((Semantic *) this, class_declaration -> identifier_token),
                           StringConstant::US_public,
                           hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                           hidden_method -> containing_type -> ExternalName());
    }
    else if (hidden_method -> ACC_PROTECTED())
    {
        if (! (method -> ACC_PROTECTED() || method -> ACC_PUBLIC()))
             ReportSemError(SemanticError::BAD_ACCESS_METHOD_OVERRIDE,
                            class_declaration -> identifier_token,
                            (class_declaration -> NumInterfaces() > 0
                                                ? class_declaration -> Interface(class_declaration -> NumInterfaces() - 1) -> RightToken()
                                                : (class_declaration -> super_opt ? class_declaration -> super_opt -> RightToken()
                                                                                  : class_declaration -> identifier_token)),
                            lex_stream -> Name(class_declaration -> identifier_token),
                            method -> Header((Semantic *) this, class_declaration -> identifier_token),
                            StringConstant::US_default,
                            method -> containing_type -> ContainingPackage() -> PackageName(),
                            method -> containing_type -> ExternalName(),
                            hidden_method -> Header((Semantic *) this, class_declaration -> identifier_token),
                            StringConstant::US_protected,
                            hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                            hidden_method -> containing_type -> ExternalName());
    }
    else if (method -> ACC_PRIVATE()) // The hidden_method method must have default access as it cannot be private...
    {
         ReportSemError(SemanticError::BAD_ACCESS_METHOD_OVERRIDE_EXTERNALLY,
                        class_declaration -> identifier_token,
                        (class_declaration -> NumInterfaces() > 0
                                            ? class_declaration -> Interface(class_declaration -> NumInterfaces() - 1) -> RightToken()
                                            : (class_declaration -> super_opt ? class_declaration -> super_opt -> RightToken()
                                                                              : class_declaration -> identifier_token)),
                        lex_stream -> Name(class_declaration -> identifier_token),
                        method -> Header((Semantic *) this, class_declaration -> identifier_token),
                        StringConstant::US_private,
                        method -> containing_type -> ContainingPackage() -> PackageName(),
                        method -> containing_type -> ExternalName(),
                        hidden_method -> Header((Semantic *) this, class_declaration -> identifier_token),
                        StringConstant::US_default,
                        hidden_method -> containing_type -> ContainingPackage() -> PackageName(),
                        hidden_method -> containing_type -> ExternalName());
    }

    CheckInheritedMethodThrows(class_declaration, method, hidden_method);

    return;
}


void Semantic::AddInheritedTypes(TypeSymbol *base_type, TypeSymbol *super_type)
{
    ExpandedTypeTable &base_expanded_table = *(base_type -> expanded_type_table),
                      &super_expanded_table = *(super_type -> expanded_type_table);

    for (int j = 0; j < super_expanded_table.symbol_pool.Length(); j++)
    {
        TypeShadowSymbol *type_shadow_symbol = super_expanded_table.symbol_pool[j];
        TypeSymbol *type_symbol = type_shadow_symbol -> type_symbol;

        //
        // Note that since all fields in an interface are implicitly public, all other fields
        // encountered here are enclosed in a type that is a super class of base_type.
        //
        if (type_symbol -> ACC_PUBLIC() ||
            type_symbol -> ACC_PROTECTED() ||
            ((! type_symbol -> ACC_PRIVATE()) &&
             (super_type -> ContainingPackage() == base_type -> ContainingPackage())))
        {
            NameSymbol *name_symbol = type_symbol -> Identity();
            TypeShadowSymbol *shadow = base_expanded_table.FindTypeShadowSymbol(name_symbol);

            if (! shadow)
                base_expanded_table.InsertTypeShadowSymbol(type_symbol);
            else if (shadow -> type_symbol -> owner != base_type)
            {
                shadow -> AddConflict(type_symbol);

                if (type_symbol -> owner != super_type) // main type doesn't override all other fields? process conflicts.
                {
                    for (int k = 0; k < type_shadow_symbol -> NumConflicts(); k++)
                        shadow -> AddConflict(type_shadow_symbol -> Conflict(k));
                }
            }
            //
            // TODO: maybe? if base_type is a nested type check if a type with the same
            //       name appears in one of the enclosed lexical scopes. If so, add 
            //       it to the shadow!
            //
        }
    }

    return;
}


void Semantic::AddInheritedFields(TypeSymbol *base_type, TypeSymbol *super_type)
{
    ExpandedFieldTable &base_expanded_table = *(base_type -> expanded_field_table),
                       &super_expanded_table = *(super_type -> expanded_field_table);

    for (int i = 0; i < super_expanded_table.symbol_pool.Length(); i++)
    {
        VariableShadowSymbol *variable_shadow_symbol = super_expanded_table.symbol_pool[i];
        VariableSymbol *variable_symbol = variable_shadow_symbol -> variable_symbol;
        //
        // Note that since all fields in an interface are implicitly public, all other fields
        // encountered here are enclosed in a type that is a super class of base_type.
        //
        if (variable_symbol -> ACC_PUBLIC() ||
            variable_symbol -> ACC_PROTECTED() ||
            ((! variable_symbol -> ACC_PRIVATE()) &&
             (super_type -> ContainingPackage() == base_type -> ContainingPackage())))
        {
            NameSymbol *name_symbol = variable_symbol -> Identity();
            VariableShadowSymbol *shadow = base_expanded_table.FindVariableShadowSymbol(name_symbol);

            if (! shadow)
                base_expanded_table.InsertVariableShadowSymbol(variable_symbol);
            else if (shadow -> variable_symbol -> owner != base_type)
            {
                shadow -> AddConflict(variable_symbol);

                if (variable_symbol -> owner != super_type) // main variable doesn't override all other fields? process conflicts.
                {
                    for (int k = 0; k < variable_shadow_symbol -> NumConflicts(); k++)
                        shadow -> AddConflict(variable_shadow_symbol -> Conflict(k));
                }
            }
        }
    }

    return;
} 


void Semantic::AddInheritedMethods(TypeSymbol *base_type, TypeSymbol *super_type, LexStream::TokenIndex tok)
{
    ExpandedMethodTable &base_expanded_table = *(base_type -> expanded_method_table),
                        &super_expanded_table = *(super_type -> expanded_method_table);

    for (int k = 0; k < super_expanded_table.symbol_pool.Length(); k++)
    {
        MethodShadowSymbol *method_shadow_symbol = super_expanded_table.symbol_pool[k];
        MethodSymbol *method = method_shadow_symbol -> method_symbol;

        //
        // Note that since all fields in an interface are implicitly
        // public, all other fields encountered here are enclosed in a
        // type that is a super class of base_type. 
        //
        if (method -> ACC_PUBLIC() ||
            method -> ACC_PROTECTED() ||
            ((! method -> ACC_PRIVATE()) && 
             (super_type -> ContainingPackage() == base_type -> ContainingPackage())))
        {
            MethodShadowSymbol *base_method_shadow =
                  base_expanded_table.FindMethodShadowSymbol(method -> Identity());
            if (! base_method_shadow)
                 base_expanded_table.InsertMethodShadowSymbol(method);
            else
            {
                MethodShadowSymbol *shadow = base_expanded_table.FindOverloadMethodShadow(method, (Semantic *) this, tok);

                if (! shadow)
                     base_expanded_table.Overload(base_method_shadow, method);
                else
                {
                    shadow -> AddConflict(method);

                    //
                    // If main method in question does not override all other methods,
                    // add all other conflicting methods.
                    //
                    if (method -> containing_type != super_type)
                    {
                        for (int i = 0; i < method_shadow_symbol -> NumConflicts(); i++)
                            shadow -> AddConflict(method_shadow_symbol -> Conflict(i));
                    }
                }
            }
        }
        else if (! (method -> ACC_PRIVATE() || method -> IsSynthetic())) // Not amethod with default access from another package?
        {
            MethodShadowSymbol *base_method_shadow = base_expanded_table.FindMethodShadowSymbol(method -> Identity());

            if (base_method_shadow)
            {
                MethodShadowSymbol *shadow = base_expanded_table.FindOverloadMethodShadow(method, (Semantic *) this, tok);

                if (shadow)
                {
                    LexStream::TokenIndex left_tok,
                                          right_tok;

                    if (ThisType() == base_type)
                    {
                        AstMethodDeclaration *method_declaration = (AstMethodDeclaration *)
                                                                    shadow -> method_symbol -> method_or_constructor_declaration;
                        AstMethodDeclarator *method_declarator = method_declaration -> method_declarator;

                        left_tok = method_declarator -> LeftToken();
                        right_tok = method_declarator -> RightToken();
                    }
                    else
                    {
                        AstInterfaceDeclaration *interface_declaration = ThisType() -> declaration -> InterfaceDeclarationCast();
                        AstClassDeclaration *class_declaration = ThisType() -> declaration -> ClassDeclarationCast();
                        if (interface_declaration)
                        {
                            left_tok = right_tok = interface_declaration -> identifier_token;
                        }
                        else if (class_declaration)
                        {
                            left_tok = right_tok = class_declaration -> identifier_token;
                        }
                        else
                        {
                            AstClassInstanceCreationExpression *class_creation = ThisType() -> declaration
                                                                                            -> ClassInstanceCreationExpressionCast();
assert(class_creation);
                            left_tok = class_creation -> class_type -> LeftToken();
                            right_tok = class_creation -> class_type -> RightToken();
                        }
                    }

                    ReportSemError(SemanticError::DEFAULT_METHOD_NOT_OVERRIDDEN,
                                   left_tok,
                                   right_tok,
                                   method -> Header((Semantic *) this, tok),
                                   base_type -> ContainingPackage() -> PackageName(),
                                   base_type -> ExternalName(),
                                   super_type -> ContainingPackage() -> PackageName(),
                                   super_type -> ExternalName());
                }
            }
        }
    }

    return;
} 


void Semantic::ComputeTypesClosure(TypeSymbol *type, LexStream::TokenIndex tok)
{
    type -> expanded_type_table = new ExpandedTypeTable();

    TypeSymbol *super_class = type -> super;
    if (super_class)
    {
        if (! super_class -> expanded_type_table)
            ComputeTypesClosure(super_class, tok);
    }

    for (int j = 0; j < type -> NumInterfaces(); j++)
    {
        TypeSymbol *interf = type -> Interface(j);
        if (! interf -> expanded_type_table)
            ComputeTypesClosure(interf, tok);
    }

    if (! type -> NestedTypesProcessed())
        type -> ProcessNestedTypeSignatures((Semantic *) this, tok);
    for (int i = 0; i < type -> NumTypeSymbols(); i++)
    {
        if (! type -> TypeSym(i) -> Bad())
            type -> expanded_type_table -> InsertTypeShadowSymbol(type -> TypeSym(i));
    }
    if (super_class)
        AddInheritedTypes(type, super_class);
    for (int k = 0; k < type -> NumInterfaces(); k++)
        AddInheritedTypes(type, type -> Interface(k));
    type -> expanded_type_table -> CompressSpace();

    return;
}


void Semantic::ComputeFieldsClosure(TypeSymbol *type, LexStream::TokenIndex tok)
{
    type -> expanded_field_table = new ExpandedFieldTable();

    TypeSymbol *super_class = type -> super;
    if (super_class)
    {
        if (! super_class -> expanded_field_table)
            ComputeFieldsClosure(super_class, tok);
    }

    for (int j = 0; j < type -> NumInterfaces(); j++)
    {
        TypeSymbol *interf = type -> Interface(j);
        if (! interf -> expanded_field_table)
            ComputeFieldsClosure(interf, tok);
    }

assert(type -> FieldMembersProcessed());

    for (int i = 0; i < type -> NumVariableSymbols(); i++)
    {
        VariableSymbol *variable = type -> VariableSym(i);
        type -> expanded_field_table -> InsertVariableShadowSymbol(variable);
    }

    //
    // As the type Object which is the super type of all interfaces does
    // not contain any field declarations, we don't have to do any special
    // check here as we have to when computing method closures.
    //
    if (super_class) 
        AddInheritedFields(type, super_class);
    for (int k = 0; k < type -> NumInterfaces(); k++)
        AddInheritedFields(type, type -> Interface(k));
    type -> expanded_field_table -> CompressSpace();

    return;
}


void Semantic::ComputeMethodsClosure(TypeSymbol *type, LexStream::TokenIndex tok)
{
    type -> expanded_method_table = new ExpandedMethodTable();

    TypeSymbol *super_class = type -> super;
    if (super_class)
    {
        if (! super_class -> expanded_method_table)
            ComputeMethodsClosure(super_class, tok);
    }

    for (int j = 0; j < type -> NumInterfaces(); j++)
    {
        TypeSymbol *interf = type -> Interface(j);

        if (! interf -> expanded_method_table)
            ComputeMethodsClosure(interf, tok);
    }

assert(type -> MethodMembersProcessed());

    for (int i = 0; i < type -> NumMethodSymbols(); i++)
    {
        MethodSymbol *method = type -> MethodSym(i);
        //
        // If the method in question is neither a constructor nor an
        // initializer, then ...
        //        if (method -> Identity() != control.init_name_symbol &&
        //            method -> Identity() != control.block_init_name_symbol &&
        //            method -> Identity() != control.clinit_name_symbol)
        //
        if (*(method -> Name()) != U_LESS)
        {
            type -> expanded_method_table -> Overload(method);
        }
    }
    if (super_class && (! type -> ACC_INTERFACE()))
        AddInheritedMethods(type, super_class, tok);
    for (int k = 0; k < type -> NumInterfaces(); k++)
        AddInheritedMethods(type, type -> Interface(k), tok);
    if (type -> ACC_INTERFACE()) // the super class is Object
        AddInheritedMethods(type, control.Object(), tok);
    type -> expanded_method_table -> CompressSpace();

    return;
}


void Semantic::ProcessFormalParameters(BlockSymbol *block, AstMethodDeclarator *method_declarator)
{
    for (int i = 0; i < method_declarator -> NumFormalParameters(); i++)
    {
        AstFormalParameter *parameter = method_declarator -> FormalParameter(i);
        AstArrayType *array_type = parameter -> type -> ArrayTypeCast();
        Ast *actual_type = (array_type ? array_type -> type : parameter -> type);

        if ((! control.option.one_one) && parameter -> NumParameterModifiers() > 0)
        {
            ReportSemError(SemanticError::ONE_ONE_FEATURE,
                           parameter -> ParameterModifier(0) -> LeftToken(),
                           parameter -> ParameterModifier(0) -> RightToken());
        }
        AccessFlags access_flags = ProcessFormalModifiers(parameter);

        AstPrimitiveType *primitive_type = actual_type -> PrimitiveTypeCast();
        TypeSymbol *parm_type = (primitive_type ? FindPrimitiveType(primitive_type) : MustFindType(actual_type));

        AstVariableDeclaratorId *name = parameter -> variable_declarator_name;
        NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(name -> identifier_token);
        VariableSymbol *symbol = block -> FindVariableSymbol(name_symbol);
        if (symbol)
        {
            ReportSemError(SemanticError::DUPLICATE_FORMAL_PARAMETER,
                           name -> identifier_token,
                           name -> identifier_token,
                           name_symbol -> Name());
        }
        else symbol = block -> InsertVariableSymbol(name_symbol);

        int num_dimensions = (array_type ? array_type -> NumBrackets() : 0) + name -> NumBrackets();
        if (num_dimensions == 0)
             symbol -> SetType(parm_type);
        else symbol -> SetType(parm_type -> GetArrayType((Semantic *) this, num_dimensions));
        symbol -> SetFlags(access_flags);
        symbol -> MarkComplete();

        parameter -> parameter_symbol = symbol;
    }

    return;
}


void Semantic::ProcessMethodDeclaration(AstMethodDeclaration *method_declaration)
{
    TypeSymbol *this_type = ThisType();
    AccessFlags access_flags = (this_type -> ACC_INTERFACE()
                                           ? ProcessAbstractMethodModifiers(method_declaration)
                                           : ProcessMethodModifiers(method_declaration));

    //
    // TODO: File Query Sun on that one. We no longer explicitly mark such methods as final
    //       as it appears that some tools expect these methods to remain unmarked.
    //
    //
    // A private method and all methods declared in a final class are implicitly final.
    //
    // if (access_flags.ACC_PRIVATE() || this_type -> ACC_FINAL())
    //    access_flags.SetACC_FINAL();
    //

    //
    // A method enclosed in an inner type may not be declared static.
    //
    if (access_flags.ACC_STATIC() && this_type -> IsInner())
    {
        AstModifier *modifier = NULL;
        for (int i = 0; i < method_declaration -> NumMethodModifiers(); i++)
        {
            if (method_declaration -> MethodModifier(i) -> kind == Ast::STATIC)
                modifier = method_declaration -> MethodModifier(i);
        }

assert(modifier);
        ReportSemError(SemanticError::STATIC_METHOD_IN_INNER_CLASS,
                       modifier -> modifier_kind_token,
                       modifier -> modifier_kind_token);
    }

    //
    //
    //
    AstArrayType *array_type = method_declaration -> type -> ArrayTypeCast();
    Ast *actual_type = (array_type ? array_type -> type : method_declaration -> type);
    AstPrimitiveType *primitive_type = actual_type -> PrimitiveTypeCast();
    TypeSymbol *method_type = (primitive_type ? FindPrimitiveType(primitive_type) : MustFindType(actual_type));

    AstMethodDeclarator *method_declarator = method_declaration -> method_declarator;
    if (method_declarator -> NumBrackets() > 0)
    {
        if (method_type == control.void_type)
             ReportSemError(SemanticError::VOID_ARRAY,
                            method_declaration -> type -> LeftToken(),
                            method_declarator -> RightToken());
        else ReportSemError(SemanticError::OBSOLESCENT_BRACKETS,
                            method_declarator -> LeftToken(),
                            method_declarator -> RightToken());
    }

    NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(method_declarator -> identifier_token);

    if (name_symbol == this_type -> Identity())
    {
        ReportSemError(SemanticError::METHOD_WITH_CONSTRUCTOR_NAME,
                       method_declaration -> type -> LeftToken(),
                       method_declarator -> identifier_token,
                       name_symbol -> Name());
    }

    //
    // As the body of the method may not have been parsed yet, we estimate a size
    // for its symbol table based on the number of lines in the body + a margin for one-liners.
    //
    AstBlock *block = method_declaration -> method_body -> BlockCast();
    BlockSymbol *block_symbol = new BlockSymbol(method_declarator -> NumFormalParameters());
    block_symbol -> max_variable_index = (access_flags.ACC_STATIC() ? 0 : 1);
    ProcessFormalParameters(block_symbol, method_declarator);

    MethodSymbol *method = this_type -> FindMethodSymbol(name_symbol);

    if (! method)
        method = this_type -> InsertMethodSymbol(name_symbol);
    else
    {
        if (this_type -> FindOverloadMethod(method, method_declarator))
        {
            ReportSemError(SemanticError::DUPLICATE_METHOD,
                           method_declarator -> LeftToken(),
                           method_declarator -> RightToken(),
                           name_symbol -> Name(),
                           this_type -> Name());
            delete block_symbol;
            return;
        }

        method = this_type -> Overload(method);
    }

    int num_dimensions = (method_type == control.void_type
                                       ? 0
                                       : (array_type ? array_type -> NumBrackets() : 0) + method_declarator -> NumBrackets());
    if (num_dimensions == 0)
         method -> SetType(method_type);
    else method -> SetType(method_type -> GetArrayType((Semantic *) this, num_dimensions));

    //
    // if the method is not static, leave a slot for the "this" pointer.
    //
    method -> SetFlags(access_flags);
    method -> SetContainingType(this_type);
    method -> SetBlockSymbol(block_symbol);
    method -> method_or_constructor_declaration = method_declaration;
    for (int i = 0; i < method_declarator -> NumFormalParameters(); i++)
    {
        AstFormalParameter *parameter = method_declarator -> FormalParameter(i);
        VariableSymbol *symbol = parameter -> parameter_symbol;

        symbol -> SetOwner(method);
        symbol -> SetLocalVariableIndex(block_symbol -> max_variable_index++);
        if (symbol -> Type() == control.long_type || symbol -> Type() == control.double_type)
            block_symbol -> max_variable_index++;
        symbol -> declarator = parameter -> variable_declarator_name;
        method -> AddFormalParameter(symbol);
    }
    method -> SetSignature(control);

    for (int k = 0; k < method_declaration -> NumThrows(); k++)
    {
        AstExpression *throw_expression = method_declaration -> Throw(k);
        TypeSymbol *throw_type = MustFindType(throw_expression);
        throw_expression -> symbol = throw_type;
        method -> AddThrows(throw_type);
    }

    method_declaration -> method_symbol = method; // save for processing bodies later.

    if (method -> ACC_ABSTRACT() && (! this_type -> ACC_ABSTRACT()))
    {
        ReportSemError(SemanticError::NON_ABSTRACT_TYPE_CONTAINS_ABSTRACT_METHOD,
                       method_declaration -> LeftToken(),
                       method_declarator -> identifier_token,
                       name_symbol -> Name(),
                       this_type -> Name());
    }

    return;
}


//
// Search for simple identifier which is supposed to be a type.
// If it is not found, issue an error message.
//
TypeSymbol *Semantic::FindPrimitiveType(AstPrimitiveType *primitive_type)
{
    switch(primitive_type -> kind)
    {
        case Ast::INT:
             return control.int_type;
        case Ast::DOUBLE:
             return control.double_type;
        case Ast::CHAR:
             return control.char_type;
        case Ast::LONG:
             return control.long_type;
        case Ast::FLOAT:
             return control.float_type;
        case Ast::BYTE:
             return control.byte_type;
        case Ast::SHORT:
             return control.short_type;
        case Ast::BOOLEAN:
             return control.boolean_type;
        default:
             break;
    }

    return control.void_type;
}


TypeSymbol *Semantic::ImportType(LexStream::TokenIndex identifier_token, NameSymbol *name_symbol)
{
    TypeSymbol *type = NULL;
    PackageSymbol *package = NULL;
    FileSymbol *file_symbol = NULL;

    for (int i = 0; i < import_on_demand_packages.Length(); i++)
    {
        PackageSymbol *import_package = import_on_demand_packages[i] -> PackageCast();

        if (import_package)
        {
            FileSymbol *symbol = Control::GetFile(import_package, name_symbol, control.option.depend);
            if (symbol)
            {
                if (! package)
                {
                    file_symbol = symbol;
                    package = import_package;
                }
                else
                {
                    ReportSemError(SemanticError::DUPLICATE_ON_DEMAND_IMPORT,
                                   identifier_token,
                                   identifier_token,
                                   name_symbol -> Name(),
                                   package -> PackageName(),
                                   import_package -> PackageName());
                }
            }
        }
        else
        {
            TypeSymbol *import_type = (TypeSymbol *) import_on_demand_packages[i];

            if (! import_type -> expanded_type_table)
                ComputeTypesClosure(import_type, identifier_token);
            TypeShadowSymbol *type_shadow_symbol = import_type -> expanded_type_table -> FindTypeShadowSymbol(name_symbol);
            if (type_shadow_symbol)
                type = FindTypeInShadow(type_shadow_symbol, identifier_token);
        }
    }

    if (! type)
    {
        if (package)
        {
            type = package -> FindTypeSymbol(name_symbol);
            if (! type)
                 type = ReadType(file_symbol, package, name_symbol, identifier_token);
            else if (type -> SourcePending())
                 control.ProcessHeaders(type -> file_symbol);
        }
    }

    if (type && (! (type -> ACC_PUBLIC() || type -> ContainingPackage() == this_package)))
        ReportTypeInaccessible(identifier_token, identifier_token, type);

    return type;
}


TypeSymbol *Semantic::FindType(LexStream::TokenIndex identifier_token)
{
    TypeSymbol *type;

    NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(identifier_token);

    SemanticEnvironment *env;
    for (env = state_stack.Top(); env; env = env -> previous)
    {
        type = env -> symbol_table.FindTypeSymbol(name_symbol);
        if (type)
            break;

        type = env -> Type();
        if (name_symbol == type -> Identity()) // Recall that a type may not have the same name as one of its enclosing types.
            break;

        if (! type -> expanded_type_table)
            ComputeTypesClosure(type, identifier_token);
        TypeShadowSymbol *type_shadow_symbol = type -> expanded_type_table -> FindTypeShadowSymbol(name_symbol);
        if (type_shadow_symbol)
        {
            type = FindTypeInShadow(type_shadow_symbol, identifier_token);
            break;
        }
    }

    if (env) // The type was found in some enclosing environment?
    {
        //
        // If the type is an inherited type, make sure that there is not a
        // type of the same name within an enclosing lexical scope.
        //
        if (type -> owner -> TypeCast() && type -> owner != env -> Type())
        {
            for (SemanticEnvironment *env2 = env -> previous; env2; env2 = env2 -> previous)
            {
                TypeSymbol *outer_type = env2 -> symbol_table.FindTypeSymbol(name_symbol); // check local type
                if (! outer_type) // if local type not found, check inner type...
                {
                    if (! env2 -> Type() -> expanded_type_table)
                        ComputeTypesClosure(env2 -> Type(), identifier_token);
                    TypeShadowSymbol *type_shadow_symbol = env2 -> Type() -> expanded_type_table
                                                                          -> FindTypeShadowSymbol(name_symbol);
                    if (type_shadow_symbol)
                        outer_type = FindTypeInShadow(type_shadow_symbol, identifier_token);
                }

                //
                // If a different type of the same name was found in an enclosing scope.
                //
                if (outer_type && outer_type != type) 
                {
                    MethodSymbol *method = outer_type -> owner -> MethodCast();

                    if (method)
                    {
                        ReportSemError(SemanticError::INHERITANCE_AND_LEXICAL_SCOPING_CONFLICT_WITH_LOCAL,
                                       identifier_token,
                                       identifier_token,
                                       lex_stream -> Name(identifier_token),
                                       env -> Type() -> ContainingPackage() -> PackageName(),
                                       env -> Type() -> ExternalName(),
                                       method -> Name());
                        break;
                    }
                    else
                    {
                        ReportSemError(SemanticError::INHERITANCE_AND_LEXICAL_SCOPING_CONFLICT_WITH_MEMBER,
                                       identifier_token,
                                       identifier_token,
                                       lex_stream -> Name(identifier_token),
                                       env -> Type() -> ContainingPackage() -> PackageName(),
                                       env -> Type() -> ExternalName(),
                                       env2 -> Type() -> ContainingPackage() -> PackageName(),
                                       env2 -> Type() -> ExternalName());
                        break;
                    }
                }
            }
        }

        return type;
    }

    //
    // check whether or not the type is in the current compilation unit
    // either because it was declared as a class or interface or it was 
    // imported by a single-type-import declaration.
    //
    for (int i = 0; i < single_type_imports.Length(); i++)
    {
        type = single_type_imports[i];
        if (name_symbol == type -> Identity())
            return type;
    }

    //
    // If a package was specified in this file (the one we are compiling),
    // we look for the type requested inside the package in question.
    // Otherwise, we look for the type requested in the unnamed package.
    //
    PackageSymbol *package = (compilation_unit -> package_declaration_opt ? this_package : control.unnamed_package);
    type = FindSimpleNameType(package, identifier_token);

    //
    // Note that a type T contained in a package P is always accessible to all other
    // types contained in P. I.e., we do not need to perform access check for type.
    //
    if (type)
    {
        //
        // If a type T was specified in a source file that is not called T.java
        // but X.java (where X != T) and we are not currently compiling file X,
        // issue a warning to alert the user that in some circumstances, this
        // may not be visible. (i.e., if the file X has not yet been compiled,
        // then T is invisile as the compiler will only look for T in T.java.)
        //
        FileSymbol *file_symbol = type -> file_symbol;
        if (file_symbol && (type -> Identity() != file_symbol -> Identity()) && (file_symbol != this -> source_file_symbol))
        {
            ReportSemError(SemanticError::REFERENCE_TO_TYPE_IN_MISMATCHED_FILE,
                           identifier_token,
                           identifier_token,
                           type -> Name(),
                           file_symbol -> Name());
        }

        return type;
    }

    //
    // check whether or not the type can be imported on demand from 
    // exactly one package or type.
    //
    return ImportType(identifier_token, name_symbol);
}


//
//
//
TypeSymbol *Semantic::MustFindType(Ast *name)
{
    TypeSymbol *type;
    LexStream::TokenIndex identifier_token;

    AstSimpleName *simple_name = name -> SimpleNameCast();
    if (simple_name)
    {
        identifier_token = simple_name -> identifier_token;
        type = FindType(identifier_token);

        //
        // If the type was not found, try to read it again to generate an appropriate error message.
        //
        if (! type)
        {
            NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(identifier_token);
            PackageSymbol *package = (compilation_unit -> package_declaration_opt ? this_package : control.unnamed_package);
            FileSymbol *file_symbol = Control::GetFile(package, name_symbol, control.option.depend);
            type = ReadType(file_symbol, package, name_symbol, identifier_token);
        }
        else
        {
             TypeAccessCheck(name, type);
        }
    }
    else
    {
        AstFieldAccess *field_access = name -> FieldAccessCast();
assert(field_access);
        identifier_token = field_access -> identifier_token;

        Symbol *symbol = ProcessPackageOrType(field_access -> base);

        type = symbol -> TypeCast();
        if (type)
        {
            TypeNestAccessCheck(field_access -> base);
            type = MustFindNestedType(type, field_access);
        }
        else
        {
            PackageSymbol *package = symbol -> PackageCast();
            if (package -> directory.Length() == 0)
            {
                ReportSemError(SemanticError::PACKAGE_NOT_FOUND,
                               field_access -> base -> LeftToken(),
                               field_access -> base -> RightToken(),
                               package -> PackageName());
            }
            NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(identifier_token);
            type = package -> FindTypeSymbol(name_symbol);
            if (! type)
            {
                FileSymbol *file_symbol = Control::GetFile(package, name_symbol, control.option.depend);
                type = ReadType(file_symbol, package, name_symbol, identifier_token);
            }
            else
            {
                if (type -> SourcePending())
                    control.ProcessHeaders(type -> file_symbol);
                TypeAccessCheck(name, type);
            }
        }
    }

    //
    // Establish a dependence from base_type to a type that it "must find".
    //
    AddDependence(ThisType(), type, identifier_token);

    return type;
}


void Semantic::ProcessInterface(AstExpression *name)
{
    TypeSymbol *interf = MustFindType(name);
assert(! interf -> SourcePending());

    if (! interf -> ACC_INTERFACE())
    {
        if (! interf -> Bad())
        {
            ReportSemError(SemanticError::NOT_AN_INTERFACE,
                           name -> LeftToken(),
                           name -> RightToken(),
                           interf -> ContainingPackage() -> PackageName(),
                           interf -> ExternalName());
        }
    }
    else
    {
        TypeSymbol *this_type = ThisType();
        int k;
        for (k = 0; k < this_type -> NumInterfaces(); k++)
            if (this_type -> Interface(k) == interf)
                break;
        if (k < this_type -> NumInterfaces())
        {
            ReportSemError(SemanticError::DUPLICATE_INTERFACE,
                           name -> LeftToken(),
                           name -> RightToken(),
                           interf -> ContainingPackage() -> PackageName(),
                           interf -> ExternalName(),
                           this_type -> ExternalName());
        }
        else
        {
            this_type -> AddInterface(interf);
        }
    }

    return;
}


void Semantic::InitializeVariable(AstFieldDeclaration *field_declaration, Tuple<VariableSymbol *> &finals)
{
    ThisMethod() = NULL;

    for (int i = 0; i < field_declaration -> NumVariableDeclarators(); i++)
    {
        AstVariableDeclarator *variable_declarator = field_declaration -> VariableDeclarator(i);

        if (ThisVariable() = variable_declarator -> symbol)
        {
            if (variable_declarator -> variable_initializer_opt)
            {
                variable_declarator -> pending = true;

                int start_num_errors = NumErrors();

                ProcessVariableInitializer(variable_declarator);
                if (NumErrors() == start_num_errors)
                     DefiniteVariableInitializer(variable_declarator, finals);
                else variable_declarator -> symbol -> MarkDefinitelyAssigned(); // assume variable is assigned

                variable_declarator -> pending = false;
            }
            ThisVariable() -> MarkComplete();
        }
    }

    return;
}


inline void Semantic::ProcessInitializer(AstBlock *initializer_block, AstBlock *block_body,
                                         MethodSymbol *init_method, Tuple<VariableSymbol *> &finals)
{
    ThisVariable() = NULL;
    ThisMethod() = init_method;

    LocalBlockStack().Push(initializer_block);
    LocalSymbolTable().Push(init_method -> block_symbol -> Table());

    int start_num_errors = NumErrors();

    AstConstructorBlock *constructor_block = block_body -> ConstructorBlockCast();
    if (constructor_block)
    {
assert(constructor_block -> explicit_constructor_invocation_opt);
        ReportSemError(SemanticError::MISPLACED_EXPLICIT_CONSTRUCTOR_INVOCATION,
                       constructor_block -> explicit_constructor_invocation_opt -> LeftToken(),
                       constructor_block -> explicit_constructor_invocation_opt -> RightToken());
    }

    ProcessBlock(block_body);

    if (NumErrors() == start_num_errors)
        DefiniteBlockInitializer(block_body, LocalBlockStack().max_size, finals);

    //
    // If an enclosed block has a higher max_variable_index than the current block,
    // update max_variable_index in the current_block, accordingly.
    //
    if (init_method -> block_symbol -> max_variable_index < LocalBlockStack().TopMaxEnclosedVariableIndex())
        init_method -> block_symbol -> max_variable_index = LocalBlockStack().TopMaxEnclosedVariableIndex();

    LocalBlockStack().Pop();
    LocalSymbolTable().Pop();

    return;
}


void Semantic::ProcessStaticInitializers(AstClassBody *class_body)
{
    if (class_body -> NumStaticInitializers() > 0 || class_body -> NumClassVariables() > 0)
    {
        TypeSymbol *this_type = ThisType();

        MethodSymbol *init_method = this_type -> InsertMethodSymbol(control.clinit_name_symbol);

        init_method -> SetType(control.void_type);
        init_method -> SetACC_FINAL();
        init_method -> SetACC_STATIC();
        init_method -> SetContainingType(this_type);
        init_method -> SetBlockSymbol(new BlockSymbol(0)); // the symbol table associated with this block will contain no element
        init_method -> block_symbol -> max_variable_index = 0;
        init_method -> SetSignature(control);

        this_type -> static_initializer_method = init_method;

        AstBlock *initializer_block = compilation_unit -> ast_pool -> GenBlock();
        initializer_block -> left_brace_token  = class_body -> left_brace_token;
        initializer_block -> right_brace_token = class_body -> left_brace_token;
        initializer_block -> block_symbol = init_method -> block_symbol;
        initializer_block -> nesting_level = LocalBlockStack().Size();

        LocalBlockStack().max_size = 0;

        //
        // Compute the set of final variables declared by the user in this type.
        //
        Tuple<VariableSymbol *> finals(this_type -> NumVariableSymbols());
        for (int l = 0; l < this_type -> NumVariableSymbols(); l++)
        {
            VariableSymbol *variable_symbol = this_type -> VariableSym(l);
            if (variable_symbol -> ACC_FINAL())
                finals.Next() = variable_symbol;
        }

        //
        // The static initializers and class variable initializers are executed in textual order... 8.5
        //
        int j,
            k;
        for (j = 0, k = 0; j < class_body -> NumClassVariables() && k < class_body -> NumStaticInitializers(); )
        {
            //
            // Note that since there cannot be any overlap in the
            // declarations, we can use either location position.
            // The RightToken of the field declaration is used because it
            // does not have to be computed (it is the terminating semicolon).
            // Similarly, the LeftToken of the static initializer is used
            // because it is the initial "static" keyword that marked the initializer.
            //
            //    if (class_body -> InstanceVariables(j) -> RightToken() < class_body -> Block(k) -> LeftToken())
            //
            if (class_body -> ClassVariable(j) -> semicolon_token < class_body -> StaticInitializer(k) -> static_token)
            {
                InitializeVariable(class_body -> ClassVariable(j), finals);
                j++;
            }
            else
            {
                AstBlock *block_body = class_body -> StaticInitializer(k) -> block;

                //
                // The first block that is the body of an initializer is reachable
                // A subsequent block is reachable iff its predecessor can complete
                // normally
                //
                block_body -> is_reachable = (k == 0
                                                 ? true
                                                 : class_body -> StaticInitializer(k - 1) -> block -> can_complete_normally);

                ProcessInitializer(initializer_block, block_body, init_method, finals);
                k++;
            }
        }
        for (; j < class_body -> NumClassVariables(); j++)
            InitializeVariable(class_body -> ClassVariable(j), finals);
        for (; k < class_body -> NumStaticInitializers(); k++)
        {
            AstBlock *block_body = class_body -> StaticInitializer(k) -> block;

            //
            // The first block that is the body of an initializer is reachable
            // A subsequent block is reachable iff its predecessor can complete
            // normally
            //
            block_body -> is_reachable = (k == 0
                                             ? true
                                             : class_body -> StaticInitializer(k - 1) -> block -> can_complete_normally);

            ProcessInitializer(initializer_block, block_body, init_method, finals);
        }

        init_method -> max_block_depth = LocalBlockStack().max_size;
        init_method -> block_symbol -> CompressSpace(); // space optimization

        //
        // Check that all static final variables have been initialized by now.
        // If not, issue an error and assume they are.
        //
        for (int i = 0; i < finals.Length(); i++)
        {
            if (finals[i] -> ACC_STATIC() && (! finals[i] -> IsDefinitelyAssigned()))
            {
                ReportSemError(SemanticError::UNINITIALIZED_STATIC_FINAL_VARIABLE,
                               finals[i] -> declarator -> LeftToken(),
                               finals[i] -> declarator -> RightToken());
                finals[i] -> MarkDefinitelyAssigned();
            }
        }

// STG:
//        delete initializer_block;
    }

    return;
}


void Semantic::ProcessBlockInitializers(AstClassBody *class_body)
{
    TypeSymbol *this_type = ThisType();

    //
    // Compute the set of final variables declared by the user in this type.
    //
    Tuple<VariableSymbol *> finals(this_type -> NumVariableSymbols());
    for (int i = 0; i < this_type -> NumVariableSymbols(); i++)
    {
        VariableSymbol *variable_symbol = this_type -> VariableSym(i);
        if (variable_symbol -> ACC_FINAL())
            finals.Next() = variable_symbol;
    }

    //
    // Initialization code is executed by every constructor, just after the
    // superclass constructor is called, in textual order along with any
    // instance variable initializations.
    //
    if (class_body -> NumBlocks() == 0)
    {
        for (int j = 0; j < class_body -> NumInstanceVariables(); j++)
            InitializeVariable(class_body -> InstanceVariable(j), finals);
    }
    else
    {
        MethodSymbol *init_method = this_type -> InsertMethodSymbol(control.block_init_name_symbol);
        init_method -> SetType(control.void_type);
        init_method -> SetACC_FINAL();
        init_method -> SetACC_PRIVATE();
        init_method -> SetContainingType(this_type);
        init_method -> SetBlockSymbol(new BlockSymbol(0));  // the symbol table associated with this block will contain no element
        init_method -> block_symbol -> max_variable_index = 1;
        init_method -> SetSignature(control);

        //
        // Compute the set of constructors whose bodies do not start with 
        // an explicit this call.
        //
        for (int i = 0; i < class_body -> NumConstructors(); i++)
        {
            MethodSymbol *method = class_body -> Constructor(i) -> constructor_symbol;
            if (method)
            {
                AstConstructorBlock *constructor_block = class_body -> Constructor(i) -> constructor_body;
                if (! (constructor_block -> explicit_constructor_invocation_opt &&
                       constructor_block -> explicit_constructor_invocation_opt -> ThisCallCast()))
                init_method -> AddInitializerConstructor(method);
            }
        }

        this_type -> block_initializer_method = init_method;

        AstBlock *initializer_block = compilation_unit -> ast_pool -> GenBlock();
        initializer_block -> left_brace_token  = class_body -> left_brace_token;
        initializer_block -> right_brace_token = class_body -> left_brace_token;
        initializer_block -> block_symbol = init_method -> block_symbol;
        initializer_block -> nesting_level = LocalBlockStack().Size();

        LocalBlockStack().max_size = 0;

        int j,
            k;
        for (j = 0, k = 0; j < class_body -> NumInstanceVariables() && k < class_body -> NumBlocks(); )
        {
            //
            // Note that since there cannot be any overlap in the
            // declarations, we can use either location position.
            // The RightToken of the field declaration is used because it
            // does not have to be computed (it is the terminating semicolon).
            // Similarly, the LeftToken of the block initializer is used
            // because it is the initial "{".
            //
            //    if (class_body -> InstanceVariable(j) -> RightToken() < class_body -> Blocks(k) -> LeftToken())
            //
            if (class_body -> InstanceVariable(j) -> semicolon_token < class_body -> Block(k) -> left_brace_token)
            {
                InitializeVariable(class_body -> InstanceVariable(j), finals);
                j++;
            }
            else
            {
                AstBlock *block_body = class_body -> Block(k);

                //
                // The first block that is the body of an initializer is reachable
                // A subsequent block is reachable iff its predecessor can complete
                // normally
                //
                block_body -> is_reachable = (k == 0 ? true : class_body -> Block(k - 1) -> can_complete_normally);

                ProcessInitializer(initializer_block, block_body, init_method, finals);
                k++;
            }
        }
        for (; j < class_body -> NumInstanceVariables(); j++)
            InitializeVariable(class_body -> InstanceVariable(j), finals);
        for (; k < class_body -> NumBlocks(); k++)
        {
            AstBlock *block_body = class_body -> Block(k);

            //
            // The first block that is the body of an initializer is reachable
            // A subsequent block is reachable iff its predecessor can complete
            // normally
            //
            block_body -> is_reachable = (k == 0 ? true : class_body -> Block(k - 1) -> can_complete_normally);

            ProcessInitializer(initializer_block, block_body, init_method, finals);
        }

        init_method -> max_block_depth = LocalBlockStack().max_size;
        init_method -> block_symbol -> CompressSpace(); // space optimization

        //
        // Note that unlike the case of static fields. We do not ensure here that
        // each final instance variable has been initialized at this point, because
        // the user may chose instead to initialize such a final variable in every
        // constructor instead. See body.cpp
        //

// STG:
//        delete initializer_block;
    }

    return;
}