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

#include "double.h"
#include "config.h"
#include <assert.h>
#include <stdio.h>
#include <math.h>
#include <sys/stat.h>
#include "parser.h"
#include "semantic.h"
#include "control.h"
#include "table.h"
#include "tuple.h"
#include "spell.h"

inline bool Semantic::IsIntValueRepresentableInType(AstExpression *expr, TypeSymbol *type)
{
    IntLiteralValue *literal = (IntLiteralValue *) expr -> value;

    return (expr -> IsConstant() && 
//
// TODO: this test makes more sense than the one below. However, the JLS
// specifies the "IsInt" test below?
//control.IsSimpleIntegerValueType(expr -> type())) &&
//
           expr -> Type() == control.int_type) &&
           (type == control.int_type ||
            type == control.no_type  ||
            (type == control.char_type && (literal -> value >= 0)  && (literal -> value <= 65535)) ||
            (type == control.byte_type && (literal -> value >= -128) && (literal -> value <= 127)) ||
            (type == control.short_type && (literal -> value >= -32768)  && (literal -> value <= 32767)));
}


inline bool Semantic::MoreSpecific(MethodSymbol *source_method, MethodSymbol *target_method)
{
    if (! CanMethodInvocationConvert(target_method -> containing_type, source_method -> containing_type))
        return false;

    for (int k = target_method -> NumFormalParameters() - 1; k >= 0; k--)
    {
        if (! CanMethodInvocationConvert(target_method -> FormalParameter(k) -> Type(),
                                         source_method -> FormalParameter(k) -> Type()))
            return false;
    }

    return true;
}


inline bool Semantic::MoreSpecific(MethodSymbol *method, Tuple<MethodSymbol *> &maximally_specific_method)
{
    for (int i = 0; i < maximally_specific_method.Length(); i++)
    {
        if (! MoreSpecific(method, maximally_specific_method[i]))
            return false;
    }

    return true;
}


inline bool Semantic::NoMethodMoreSpecific(Tuple<MethodSymbol *> &maximally_specific_method, MethodSymbol *method)
{
    for (int i = 0; i < maximally_specific_method.Length(); i++)
    {
        if (MoreSpecific(maximally_specific_method[i], method))
            return false;
    }

    return true;
}


void Semantic::ReportMethodNotFound(Ast *ast, wchar_t *name)
{
    SemanticError::SemanticErrorKind kind;

    int num_arguments;
    AstExpression **argument;

    AstMethodInvocation *method_call;
    AstClassInstanceCreationExpression *class_creation;
    AstThisCall *this_call;
    AstSuperCall *super_call;
    if (method_call = ast -> MethodInvocationCast())
    {
        kind = SemanticError::METHOD_NOT_FOUND;
        num_arguments = method_call -> NumArguments();
        argument = new AstExpression*[num_arguments + 1];
        for (int i = 0; i < num_arguments; i++)
            argument[i] = method_call -> Argument(i);
    }
    else
    {
        kind = SemanticError::CONSTRUCTOR_NOT_FOUND;

        if (class_creation = ast -> ClassInstanceCreationExpressionCast())
        {
            num_arguments = class_creation -> NumArguments();
            argument = new AstExpression*[num_arguments + 1];
            for (int i = 0; i < num_arguments; i++)
                argument[i] = class_creation -> Argument(i);
        }
        else if (super_call = ast -> SuperCallCast())
        {
            num_arguments = super_call -> NumArguments();
            argument = new AstExpression*[num_arguments + 1];
            for (int i = 0; i < num_arguments; i++)
                argument[i] = super_call -> Argument(i);
        }
        else
        {
            this_call = ast -> ThisCallCast();
assert(this_call);
            num_arguments = this_call -> NumArguments();
            argument = new AstExpression*[num_arguments + 1];
            for (int i = 0; i < num_arguments; i++)
                argument[i] = this_call -> Argument(i);
        }
    }

    int length = wcslen(name);

    for (int i = 0; i < num_arguments; i++)
    {
        TypeSymbol *arg_type = argument[i] -> Type();
        length += arg_type -> ContainingPackage() -> PackageNameLength() +
                  arg_type -> ExternalNameLength() + 3; // '/' after package_name
                                                        // ',' and ' ' to separate this formal parameter from the next one
    }

    wchar_t *header = new wchar_t[length + 3]; // +1 for (, +1 for ), +1 for '\0'
    wchar_t *s = header;

    for (wchar_t *s2 = name; *s2; s2++)
         *s++ = *s2;
    *s++ = U_LEFT_PARENTHESIS;
    if (num_arguments > 0)
    {
        for (int i = 0; i < num_arguments; i++)
        {
            TypeSymbol *arg_type = argument[i] -> Type();

            PackageSymbol *package = arg_type -> ContainingPackage();
            wchar_t *package_name = package -> PackageName();
            if (package -> PackageNameLength() > 0 && wcscmp(package_name, StringConstant::US__DO_) != 0)
            {
                while (*package_name)
                {
                    *s++ = (*package_name == U_SLASH ? (wchar_t) U_DOT : *package_name);
                    package_name++;
                }
                *s++ = U_DOT;
            }

            for (wchar_t *s2 = arg_type -> ExternalName(); *s2; s2++)
                *s++ = (*s2 == U_DOLLAR ? (wchar_t) U_DOT : *s2);
            *s++ = U_COMMA;
            *s++ = U_SPACE;
        }

        s -= 2; // remove the last ',' and ' '
    }
    *s++ = U_RIGHT_PARENTHESIS;
    *s = U_NULL;

    ReportSemError(kind,
                   ast -> LeftToken(),
                   ast -> RightToken(),
                   header);

    delete [] header;
    delete [] argument;

    return;
}


MethodSymbol *Semantic::FindConstructor(TypeSymbol *containing_type, Ast *ast,
                                        LexStream::TokenIndex left_tok, LexStream::TokenIndex right_tok)
{
    Tuple<MethodSymbol *> constructor_set(2);

    int num_arguments;
    AstExpression **argument; 

    AstClassInstanceCreationExpression *class_creation;
    AstThisCall *this_call;
    AstSuperCall *super_call;
    if (class_creation = ast -> ClassInstanceCreationExpressionCast())
    {
        num_arguments = class_creation -> NumArguments();
        argument = new AstExpression*[num_arguments + 1];
        for (int i = 0; i < num_arguments; i++)
            argument[i] = class_creation -> Argument(i);
    }
    else if (super_call = ast -> SuperCallCast())
    {
        num_arguments = super_call -> NumArguments();
        argument = new AstExpression*[num_arguments + 1];
        for (int i = 0; i < num_arguments; i++)
            argument[i] = super_call -> Argument(i);
    }
    else
    {
        this_call = ast -> ThisCallCast();
assert(this_call);
        num_arguments = this_call -> NumArguments();
        argument = new AstExpression*[num_arguments + 1];
        for (int i = 0; i < num_arguments; i++)
            argument[i] = this_call -> Argument(i);
    }

assert(containing_type -> ConstructorMembersProcessed());

    for (MethodSymbol *constructor = containing_type -> FindConstructorSymbol();
         constructor; constructor = constructor -> next_method)
    {
        if (! constructor -> IsTyped())
            constructor -> ProcessMethodSignature((Semantic *) this, right_tok);

        if (num_arguments == constructor -> NumFormalParameters())
        {
            int i;
            for (i = 0; i < num_arguments; i++)
            {
                if (! CanMethodInvocationConvert(constructor -> FormalParameter(i) -> Type(), argument[i] -> Type()))
                    break;
            }
            if (i == num_arguments)
            {
                if (MoreSpecific(constructor, constructor_set))
                {
                    constructor_set.Reset();
                    constructor_set.Next() = constructor;
                }
                else if (NoMethodMoreSpecific(constructor_set, constructor))
                    constructor_set.Next() = constructor;
            }
        }
    }

    if (constructor_set.Length() == 0)
    {
        MethodSymbol *method;
        for (method = containing_type -> FindMethodSymbol(containing_type -> Identity()); method; method = method -> next_method)
        {
            if (! method -> IsTyped())
                method -> ProcessMethodSignature((Semantic *) this, right_tok);

            if (num_arguments == method -> NumFormalParameters())
            {
                int i;
                for (i = 0; i < num_arguments; i++)
                {
                    if (! CanMethodInvocationConvert(method -> FormalParameter(i) -> Type(), argument[i] -> Type()))
                        break;
                }
                if (i == num_arguments)
                    break;
            }
        }

        if (method)
        {
            if (method -> method_or_constructor_declaration)
            {
                AstMethodDeclaration *method_declaration = (AstMethodDeclaration *) method -> method_or_constructor_declaration;
                FileLocation loc(method -> containing_type -> semantic_environment -> sem -> lex_stream,
                                 method_declaration -> method_declarator -> identifier_token);

                ReportSemError(SemanticError::METHOD_FOUND_FOR_CONSTRUCTOR,
                               left_tok,
                               right_tok,
                               containing_type -> Name(),
                               loc.location);
            }
            else
            {
                ReportSemError(SemanticError::METHOD_FOUND_FOR_CONSTRUCTOR,
                               left_tok,
                               right_tok,
                               containing_type -> Name(),
                               method -> containing_type -> file_location -> location);
            }
        }
        else ReportMethodNotFound(ast, containing_type -> Name());

        delete [] argument;

        return (MethodSymbol *) NULL;
    }
    else if (constructor_set.Length() > 1)
    {
        ReportSemError(SemanticError::AMBIGUOUS_CONSTRUCTOR_INVOCATION,
                       left_tok,
                       right_tok,
                       containing_type -> Name());
    }

    delete [] argument;

    return constructor_set[0];
}


//
//
//
VariableSymbol *Semantic::FindMisspelledVariableName(TypeSymbol *type, LexStream::TokenIndex identifier_token)
{
    VariableSymbol *misspelled_variable = NULL;
    int index = 0;
    NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(identifier_token);

    for (int k = 0; k < type -> expanded_field_table -> symbol_pool.Length(); k++)
    {
        VariableShadowSymbol *variable_shadow = type -> expanded_field_table -> symbol_pool[k];
        VariableSymbol *variable = variable_shadow -> variable_symbol;
        if (! variable -> IsTyped())
            variable -> ProcessVariableSignature((Semantic *) this, identifier_token);

        int new_index = Spell::Index(name_symbol -> Name(), variable -> Name());
        if (new_index > index)
        {
            misspelled_variable = variable;
            index = new_index;
        }
    }

    int length = name_symbol -> NameLength();

    return ((length == 3 && index >= 5) || (length == 4 && index >= 6) || (length >= 5 && index >= 7)
                          ? misspelled_variable
                          : NULL);
}

//
//
//
MethodSymbol *Semantic::FindMisspelledMethodName(TypeSymbol *type, AstMethodInvocation *method_call, NameSymbol *name_symbol)
{
    MethodSymbol *misspelled_method = NULL;
    int index = 0;
    AstSimpleName *simple_name = method_call -> method -> SimpleNameCast();
    AstFieldAccess *field_access = method_call -> method -> FieldAccessCast();
    LexStream::TokenIndex identifier_token = (simple_name ? simple_name -> identifier_token : field_access -> identifier_token);

    for (int k = 0; k < type -> expanded_method_table -> symbol_pool.Length(); k++)
    {
        MethodShadowSymbol *method_shadow = type -> expanded_method_table -> symbol_pool[k];
        MethodSymbol *method = method_shadow -> method_symbol;
        TypeSymbol *containing_type = method -> containing_type;

        if (! method -> IsTyped())
            method -> ProcessMethodSignature((Semantic *) this, identifier_token);

        if (method_call -> NumArguments() == method -> NumFormalParameters())
        {
            int i;
            for (i = 0; i < method_call -> NumArguments(); i++)
            {
                AstExpression *expr =  method_call -> Argument(i);
                if (! CanMethodInvocationConvert(method -> FormalParameter(i) -> Type(), expr -> Type()))
                    break;
            }
            if (i == method_call -> NumArguments())
            {
                int new_index = Spell::Index(name_symbol -> Name(), method -> Name());
                if (new_index > index)
                {
                    misspelled_method = method;
                    index = new_index;
                }
            }
        }
    }

    int length = name_symbol -> NameLength(),
         num_args = method_call -> NumArguments();

    //
    // If we have a name of length 2, accept >= 30% probality if the function takes at least one argument
    // If we have a name of length 3, accept >= 50% probality if the function takes at least one argument
    // Otherwise, if the length of the name is > 3, accept >= 60% probability.
    //
    return (index < 3 ? NULL
                      : (length == 2 && (index >= 3 || num_args > 0)) ||
                        (length == 3 && (index >= 5 || num_args > 0)) ||
                        (length  > 3 && (index >= 6 || (index >= 5 && num_args > 0)))
                                     ? misspelled_method
                                     : NULL);
}

//
// Search the type in question for a method. Note that name_symbol is an optional argument.
// If it was not passed to this function then its default value is NULL (see semantic.h) and
// we assume that the name to search for is the name specified in the field_access of the
// method_call. 
//
MethodSymbol *Semantic::FindMethodInType(TypeSymbol *type, AstMethodInvocation *method_call, NameSymbol *name_symbol)
{
    Tuple<MethodSymbol *> method_set(2);
    AstFieldAccess *field_access = method_call -> method -> FieldAccessCast();
    if (! name_symbol)
        name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token);

    if (! type -> expanded_method_table)
        ComputeMethodsClosure(type, field_access -> identifier_token);

//
// TODO: Confirm that this is no longer the case as of javac 1.2
//
/*
    //
    // First look for the method in the "type". If it is not found, look for
    // it in the superclasses in the proper order. It is possible that the
    // method in question is a private field that is contained in the body
    // of the type that we are currently processing (this_type()), in which
    // case it is accessible even though it is not directly inherited by "type".
    //
    for (TypeSymbol *type_symbol = type; type_symbol && method_set.Length() == 0; type_symbol = type_symbol -> super)
    {
*/
        TypeSymbol *type_symbol = type;

        for (MethodShadowSymbol *method_shadow = type_symbol -> expanded_method_table -> FindMethodShadowSymbol(name_symbol);
             method_shadow; method_shadow = method_shadow -> next_method)
        {
            MethodSymbol *method = method_shadow -> method_symbol;
            TypeSymbol *containing_type = method -> containing_type;

            if (! method -> IsTyped())
                method -> ProcessMethodSignature((Semantic *) this, field_access -> identifier_token);

            if (method_call -> NumArguments() == method -> NumFormalParameters())
            {
                int i;
                for (i = 0; i < method_call -> NumArguments(); i++)
                {
                    AstExpression *expr =  method_call -> Argument(i);
                    if (! CanMethodInvocationConvert(method -> FormalParameter(i) -> Type(), expr -> Type()))
                        break;
                }
                if (i == method_call -> NumArguments())
                {
                    if (MoreSpecific(method, method_set))
                    {
                        method_set.Reset();
                        method_set.Next() = method;
                    }
                    else if (NoMethodMoreSpecific(method_set, method))
                        method_set.Next() = method;
                }
            }
        }

/*
See comment above...
    }
*/

    if (method_set.Length() == 0)
    {
        if (! type -> expanded_field_table)
            ComputeFieldsClosure(type, field_access -> identifier_token);

        VariableShadowSymbol *variable_shadow_symbol = type -> expanded_field_table -> FindVariableShadowSymbol(name_symbol);

        if (variable_shadow_symbol)
        {
            VariableSymbol *variable_symbol = variable_shadow_symbol -> variable_symbol;
            TypeSymbol *enclosing_type = variable_symbol -> owner -> TypeCast();
assert(enclosing_type);
            ReportSemError(SemanticError::FIELD_NOT_METHOD,
                           method_call -> LeftToken(),
                           method_call -> RightToken(),
                           variable_symbol -> Name(),
                           enclosing_type -> ContainingPackage() -> PackageName(),
                           enclosing_type -> ExternalName());
        }
        else
        {
            TypeSymbol *super_type;
            MethodShadowSymbol *method_shadow;

            for (super_type = type -> super; super_type; super_type = super_type -> super)
            {
                for (method_shadow = super_type -> expanded_method_table -> FindMethodShadowSymbol(name_symbol);
                     method_shadow; method_shadow = method_shadow -> next_method)
                {
                    MethodSymbol *method = method_shadow -> method_symbol;
                    if (! method -> IsTyped())
                        method -> ProcessMethodSignature((Semantic *) this, field_access -> identifier_token);

                    if (method_call -> NumArguments() == method -> NumFormalParameters())
                    {
                        int i;
                        for (i = 0; i < method_call -> NumArguments(); i++)
                        {
                            AstExpression *expr =  method_call -> Argument(i);
                            if (! CanMethodInvocationConvert(method -> FormalParameter(i) -> Type(), expr -> Type()))
                                break;
                        }
                        if (i == method_call -> NumArguments()) // found a match ?
                            break;
                    }
                }

                if (method_shadow) // found a match ?
                    break;
            }

            if (super_type)
            {
                ReportSemError((method_shadow -> method_symbol -> ACC_PRIVATE()
                                               ? SemanticError::METHOD_WITH_PRIVATE_ACCESS_NOT_ACCESSIBLE
                                               : SemanticError::METHOD_WITH_DEFAULT_ACCESS_NOT_ACCESSIBLE),
                               method_call -> LeftToken(),
                               method_call -> RightToken(),
                               name_symbol -> Name(),
                               super_type -> ContainingPackage() -> PackageName(),
                               super_type -> ExternalName(),
                               type -> ContainingPackage() -> PackageName(),
                               type -> ExternalName());
            }
            else
            {
                if (FindNestedType(type, field_access -> identifier_token))
                {
                    ReportSemError(SemanticError::TYPE_NOT_METHOD,
                                   method_call -> LeftToken(),
                                   method_call -> RightToken(),
                                   name_symbol -> Name());
                }
                else if (type -> expanded_method_table -> FindMethodShadowSymbol(name_symbol))
                    ReportMethodNotFound(method_call, name_symbol -> Name());
                else
                {
                    MethodSymbol *method = FindMisspelledMethodName(type, method_call, name_symbol);
                    if (method)
                         ReportSemError(SemanticError::METHOD_NAME_MISSPELLED,
                                        method_call -> LeftToken(),
                                        method_call -> RightToken(),
                                        name_symbol -> Name(),
                                        type -> ContainingPackage() -> PackageName(),
                                        type -> ExternalName(),
                                        method -> Name());
                    else ReportSemError(SemanticError::METHOD_NAME_NOT_FOUND_IN_TYPE,
                                        method_call -> LeftToken(),
                                        method_call -> RightToken(),
                                        name_symbol -> Name(),
                                        type -> ContainingPackage() -> PackageName(),
                                        type -> ExternalName());
                }
            }
        }

        return (MethodSymbol *) NULL;
    }
    else if (method_set.Length() > 1)
    {
        ReportSemError(SemanticError::AMBIGUOUS_METHOD_INVOCATION,
                       method_call -> LeftToken(),
                       method_call -> RightToken(),
                       name_symbol -> Name(),
                       method_set[0] -> Header(),
                       method_set[0] -> containing_type -> ContainingPackage() -> PackageName(),
                       method_set[0] -> containing_type -> ExternalName(),
                       method_set[1] -> Header(),
                       method_set[1] -> containing_type -> ContainingPackage() -> PackageName(),
                       method_set[1] -> containing_type -> ExternalName());
    }

    MethodSymbol *method = method_set[0];
    if (method -> IsSynthetic())
    {
        ReportSemError(SemanticError::SYNTHETIC_METHOD_INVOCATION,
                       method_call -> LeftToken(),
                       method_call -> RightToken(),
                       method -> Header(),
                       method -> containing_type -> ContainingPackage() -> PackageName(),
                       method -> containing_type -> ExternalName());
    }

    return method;
}


void Semantic::SearchForMethodInEnvironment(Tuple<MethodSymbol *> &methods_found,
                                            SemanticEnvironment *&where_found,
                                            SemanticEnvironment *stack,
                                            AstMethodInvocation *method_call)
{
    AstSimpleName *simple_name = method_call -> method -> SimpleNameCast();
    NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(simple_name -> identifier_token);

    for (SemanticEnvironment *env = stack; env; env = env -> previous)
    {
        TypeSymbol *type = env -> Type();
        if (! type -> expanded_method_table)
            ComputeMethodsClosure(type, simple_name -> identifier_token);

        methods_found.Reset();
        where_found = NULL;

        //
        // If this environment contained a method with the right name, the search stops:
        //
        //    "Class scoping does not influence overloading: if the inner class has one
        //     print method, the simple method name 'print' refers to that method, not 
        //     any of the ten 'print' methods in the enclosing class."
        //
        MethodShadowSymbol *method_shadow = type -> expanded_method_table -> FindMethodShadowSymbol(name_symbol);
        if (method_shadow)
        {
            for (; method_shadow; method_shadow = method_shadow -> next_method)
            {
                MethodSymbol *method = method_shadow -> method_symbol;
                TypeSymbol *containing_type = method -> containing_type;

                if (! method -> IsTyped())
                    method -> ProcessMethodSignature((Semantic *) this, simple_name -> identifier_token);

                //
                // Since type -> IsOwner(this_type()), i.e., type encloses this_type(),
                // method is accessible, even if it is private.
                //
                if (method_call -> NumArguments() == method -> NumFormalParameters())
                {
                    int i;
                    for (i = 0; i < method_call -> NumArguments(); i++)
                    {
                        AstExpression *expr =  method_call -> Argument(i);
                        if (! CanMethodInvocationConvert(method -> FormalParameter(i) -> Type(), expr -> Type()))
                            break;
                    }
                    if (i == method_call -> NumArguments())
                    {
                        if (MoreSpecific(method, methods_found))
                        {
                            methods_found.Reset();
                            methods_found.Next() = method;
                        }
                        else if (NoMethodMoreSpecific(methods_found, method))
                            methods_found.Next() = method;
                    }
                }
            }

            //
            // If a match was found, save the environment
            //
            where_found = (methods_found.Length() > 0 ? env : NULL);
            break;
        }
    }

    return;
}


MethodSymbol *Semantic::FindMethodInEnvironment(SemanticEnvironment *&where_found,
                                                SemanticEnvironment *stack,
                                                AstMethodInvocation *method_call)
{
    Tuple<MethodSymbol *> methods_found(2);
    SearchForMethodInEnvironment(methods_found, where_found, stack, method_call);

    MethodSymbol *method_symbol = (methods_found.Length() > 0 ? methods_found[0] : (MethodSymbol *) NULL);
    if (method_symbol)
    {
        for (int i = 1; i < methods_found.Length(); i++)
        {
            ReportSemError(SemanticError::AMBIGUOUS_METHOD_INVOCATION,
                           method_call -> LeftToken(),
                           method_call -> RightToken(),
                           method_symbol -> Name(),
                           methods_found[0] -> Header(),
                           method_symbol -> containing_type -> ContainingPackage() -> PackageName(),
                           method_symbol -> containing_type -> ExternalName(),
                           methods_found[i] -> Header(),
                           methods_found[i] -> containing_type -> ContainingPackage() -> PackageName(),
                           methods_found[i] -> containing_type -> ExternalName());
        }

        if (method_symbol -> containing_type != where_found -> Type())  // is symbol an inherited field?
        {
            if (method_symbol -> IsSynthetic())
            {
                ReportSemError(SemanticError::SYNTHETIC_METHOD_INVOCATION,
                               method_call -> LeftToken(),
                               method_call -> RightToken(),
                               method_symbol -> Header(),
                               method_symbol -> containing_type -> ContainingPackage() -> PackageName(),
                               method_symbol -> containing_type -> ExternalName());
            }
            else
            {
                for (SemanticEnvironment *env = where_found -> previous; env; env = env -> previous)
                {
                    Tuple<MethodSymbol *> others(2);
                    SemanticEnvironment *found_other;
                    SearchForMethodInEnvironment(others, found_other, env, method_call);

                    int i;
                    for (i = 0; i < others.Length();  i++)
                    {
                        if (others[i] != method_symbol)
                        {
                            ReportSemError(SemanticError::INHERITANCE_AND_LEXICAL_SCOPING_CONFLICT_WITH_MEMBER,
                                           method_call -> LeftToken(),
                                           method_call -> RightToken(),
                                           method_symbol -> Name(),
                                           method_symbol -> containing_type -> ContainingPackage() -> PackageName(),
                                           method_symbol -> containing_type -> ExternalName(),
                                           found_other -> Type() -> ContainingPackage() -> PackageName(),
                                           found_other -> Type() -> ExternalName());
                            break;
                        }
                    }

                    if (i < others.Length()) // as soon as we find an error, bail out...
                        break;
                }
            }
        }
    }
    else
    {
        AstSimpleName *simple_name = method_call -> method -> SimpleNameCast();
        NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(simple_name -> identifier_token);
        bool symbol_found = false;

        //
        // First, search for a perfect visible method match in an enclosing class.
        //
assert(stack);
        for (SemanticEnvironment *env = stack -> previous; env; env = env -> previous)
        {
            Tuple<MethodSymbol *> others(2);
            SemanticEnvironment *found_other;
            SearchForMethodInEnvironment(others, found_other, env, method_call);

            if (others.Length() > 0)
            {
                ReportSemError(SemanticError::HIDDEN_METHOD_IN_ENCLOSING_CLASS,
                               method_call -> LeftToken(),
                               method_call -> RightToken(),
                               others[0] -> Header(),
                               others[0] -> containing_type -> ContainingPackage() -> PackageName(),
                               others[0] -> containing_type -> ExternalName());

                symbol_found = true;
                break;
            }
        }

        //
        // If a method in an enclosing class was not found. Search for a similar visible field 
        // or a private method with the name.
        //
        for (SemanticEnvironment *env2 = stack; env2 && (! symbol_found); env2 = env2 -> previous)
        {
            TypeSymbol *type = env2 -> Type();

            if (! type -> expanded_field_table)
                ComputeFieldsClosure(type, simple_name -> identifier_token);

            VariableShadowSymbol *variable_shadow_symbol = type -> expanded_field_table -> FindVariableShadowSymbol(name_symbol);
            if (variable_shadow_symbol)
            {
                VariableSymbol *variable_symbol = variable_shadow_symbol -> variable_symbol;
                TypeSymbol *enclosing_type = variable_symbol -> owner -> TypeCast();
assert(enclosing_type);
                ReportSemError(SemanticError::FIELD_NOT_METHOD,
                               method_call -> LeftToken(),
                               method_call -> RightToken(),
                               variable_symbol -> Name(),
                               enclosing_type -> ContainingPackage() -> PackageName(),
                               enclosing_type -> ExternalName());
                symbol_found = true;
                break;
            }
            else
            {
                TypeSymbol *super_type;
                MethodShadowSymbol *method_shadow;

                for (super_type = type -> super; super_type; super_type = super_type -> super)
                {
                    for (method_shadow = super_type -> expanded_method_table -> FindMethodShadowSymbol(name_symbol);
                         method_shadow; method_shadow = method_shadow -> next_method)
                    {
                        MethodSymbol *method = method_shadow -> method_symbol;
                        if (! method -> IsTyped())
                            method -> ProcessMethodSignature((Semantic *) this, simple_name -> identifier_token);

                        if (method_call -> NumArguments() == method -> NumFormalParameters())
                        {
                            int i;
                            for (i = 0; i < method_call -> NumArguments(); i++)
                            {
                                AstExpression *expr = method_call -> Argument(i);
                                if (! CanMethodInvocationConvert(method -> FormalParameter(i) -> Type(), expr -> Type()))
                                    break;
                            }
                            if (i == method_call -> NumArguments()) // found a match ?
                                break;
                        }
                    }

                    if (method_shadow) // found a match ?
                        break;
                }

                if (super_type)
                {
                    ReportSemError((method_shadow -> method_symbol -> ACC_PRIVATE()
                                                   ? SemanticError::METHOD_WITH_PRIVATE_ACCESS_NOT_ACCESSIBLE
                                                   : SemanticError::METHOD_WITH_DEFAULT_ACCESS_NOT_ACCESSIBLE),
                                   method_call -> LeftToken(),
                                   method_call -> RightToken(),
                                   name_symbol -> Name(),
                                   super_type -> ContainingPackage() -> PackageName(),
                                   super_type -> ExternalName(),
                                   type -> ContainingPackage() -> PackageName(),
                                   type -> ExternalName());
                    symbol_found = true;
                    break;
                }    
            }
        }

        //
        // Finally, if we did not find a method or field name that matches, look for a type
        // with that name.
        //
        if (! symbol_found)
        {
            TypeSymbol *this_type = ThisType();

            if (FindType(simple_name -> identifier_token))
            {
                ReportSemError(SemanticError::TYPE_NOT_METHOD,
                               method_call -> LeftToken(),
                               method_call -> RightToken(),
                               name_symbol -> Name());
            }
            else if (this_type -> expanded_method_table -> FindMethodShadowSymbol(name_symbol))
                ReportMethodNotFound(method_call, name_symbol -> Name());
            else
            {
                MethodSymbol *method = FindMisspelledMethodName(this_type, method_call, name_symbol);
                if (method)
                     ReportSemError(SemanticError::METHOD_NAME_MISSPELLED,
                                    method_call -> LeftToken(),
                                    method_call -> RightToken(),
                                    name_symbol -> Name(),
                                    this_type -> ContainingPackage() -> PackageName(),
                                    this_type -> ExternalName(),
                                    method -> Name());
                else ReportSemError(SemanticError::METHOD_NAME_NOT_FOUND_IN_TYPE,
                                    method_call -> LeftToken(),
                                    method_call -> RightToken(),
                                    name_symbol -> Name(),
                                    this_type -> ContainingPackage() -> PackageName(),
                                    this_type -> ExternalName());
            }
        }
    }

    return method_symbol;
}



//
// Search the type in question for a variable. Note that name_symbol is an optional argument.
// If it was not passed to this function then its default value is NULL (see semantic.h) and
// we assume that the name to search for is the last identifier specified in the field_access.
//
inline VariableSymbol *Semantic::FindVariableInType(TypeSymbol *type, AstFieldAccess *field_access, NameSymbol *name_symbol)
{
    if (! name_symbol)
        name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token);

    if (! type -> expanded_field_table)
        ComputeFieldsClosure(type, field_access -> identifier_token);

//
// TODO: Confirm that this is no longer the case as of javac 1.2
//
/*
    //
    // First look for the variable in the "type". If it is not found, look for
    // it in the superclasses in the proper order. It is possible that the
    // field in question is a private field that is contained in the body
    // of the type that we are currently processing (this_type()), in which case
    // it is accessible even though it is not directly inherited by "type".
    //
    VariableShadowSymbol *variable_shadow_symbol;
    for (variable_shadow_symbol = NULL; (! variable_shadow_symbol) && type; type = type -> super)
        variable_shadow_symbol = type -> expanded_field_table -> FindVariableShadowSymbol(name_symbol);
*/

    VariableShadowSymbol *variable_shadow_symbol = type -> expanded_field_table -> FindVariableShadowSymbol(name_symbol);

    //
    // 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).
    //
    if (variable_shadow_symbol)
    {
        VariableSymbol *variable_symbol = variable_shadow_symbol -> variable_symbol;

        for (int i = 0; i < variable_shadow_symbol -> NumConflicts(); i++)
        {
            ReportSemError(SemanticError::AMBIGUOUS_NAME,
                           field_access -> LeftToken(),
                           field_access -> RightToken(),
                           name_symbol -> Name(),
                           variable_symbol -> owner -> TypeCast() -> ContainingPackage() -> PackageName(),
                           variable_symbol -> owner -> TypeCast() -> ExternalName(),
                           variable_shadow_symbol -> Conflict(i) -> owner -> TypeCast() -> ContainingPackage() -> PackageName(),
                           variable_shadow_symbol -> Conflict(i) -> owner -> TypeCast() -> ExternalName());
        }

        if (variable_symbol -> IsSynthetic())
        {
            ReportSemError(SemanticError::SYNTHETIC_VARIABLE_ACCESS,
                           field_access -> LeftToken(),
                           field_access -> RightToken(),
                           variable_symbol -> Name(),
                           variable_symbol -> owner -> TypeCast() -> ContainingPackage() -> PackageName(),
                           variable_symbol -> owner -> TypeCast() -> ExternalName());
        }
        return variable_symbol;
    }

    return (VariableSymbol *) NULL;
}


void Semantic::ReportAccessedFieldNotFound(AstFieldAccess *field_access, TypeSymbol *type)
{
    NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token);
    VariableShadowSymbol *variable_shadow_symbol;

    if (! type -> expanded_field_table)
        ComputeFieldsClosure(type, field_access -> base -> LeftToken());
    TypeSymbol *super_type;
    for (super_type = type -> super; super_type; super_type = super_type -> super)
    {
        variable_shadow_symbol = super_type -> expanded_field_table -> FindVariableShadowSymbol(name_symbol);
        if (variable_shadow_symbol)
            break;
    }

    if (super_type)
    {
        VariableSymbol *variable_symbol = variable_shadow_symbol -> variable_symbol;
        ReportSemError((variable_symbol -> ACC_PRIVATE()
                                         ? SemanticError::FIELD_WITH_PRIVATE_ACCESS_NOT_ACCESSIBLE
                                         : SemanticError::FIELD_WITH_DEFAULT_ACCESS_NOT_ACCESSIBLE),
                       field_access -> LeftToken(),
                       field_access -> RightToken(),
                       variable_symbol -> Name(),
                       super_type -> ContainingPackage() -> PackageName(),
                       super_type -> ExternalName(),
                       type -> ContainingPackage() -> PackageName(),
                       type -> ExternalName());
    }    
    else
    {
        VariableSymbol *variable = FindMisspelledVariableName(type, field_access -> identifier_token);
        if (variable)
             ReportSemError(SemanticError::FIELD_NAME_MISSPELLED,
                            field_access -> LeftToken(),
                            field_access -> RightToken(),
                            name_symbol -> Name(),
                            type -> ContainingPackage() -> PackageName(),
                            type -> ExternalName(),
                            variable -> Name());
        else ReportSemError(SemanticError::FIELD_NOT_FOUND,
                            field_access -> LeftToken(),
                            field_access -> RightToken(),
                            lex_stream -> Name(field_access -> identifier_token),
                            type -> ContainingPackage() -> PackageName(),
                            type -> ExternalName());
    }

    return;
}


void Semantic::SearchForVariableInEnvironment(Tuple<VariableSymbol *> &variables_found,
                                              SemanticEnvironment *&where_found,
                                              SemanticEnvironment *stack,
                                              NameSymbol *name_symbol,
                                              LexStream::TokenIndex identifier_token)
{
    variables_found.Reset();
    where_found = (SemanticEnvironment *) NULL;

    for (SemanticEnvironment *env = stack; env; env = env -> previous)
    {
        VariableSymbol *variable_symbol = env -> symbol_table.FindVariableSymbol(name_symbol);
        if (variable_symbol) // a local variable
        {
            variables_found.Next() = variable_symbol;
            where_found = env;
            break;
        }

        TypeSymbol *type = env -> Type();
        if (! type -> expanded_field_table)
            ComputeFieldsClosure(type, identifier_token);
        VariableShadowSymbol *variable_shadow_symbol = type -> expanded_field_table -> FindVariableShadowSymbol(name_symbol);
        if (variable_shadow_symbol) 
        {
            //
            // Since type -> IsOwner(this_type()), i.e., type encloses this_type(),
            // variable_symbol is accessible, even if it is private.
            //
            variables_found.Next() = variable_shadow_symbol -> variable_symbol;

            //
            // 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).
            //
            for (int i = 0; i < variable_shadow_symbol -> NumConflicts(); i++)
                variables_found.Next() = variable_shadow_symbol -> Conflict(i);
            where_found = env;
            break;
        }
    }

    return;
}


VariableSymbol *Semantic::FindVariableInEnvironment(SemanticEnvironment *&where_found,
                                                    SemanticEnvironment *stack, LexStream::TokenIndex identifier_token)
{
    Tuple<VariableSymbol *> variables_found(2);
    NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(identifier_token);
    SearchForVariableInEnvironment(variables_found, where_found, stack, name_symbol, identifier_token);

    VariableSymbol *variable_symbol = (VariableSymbol *) (variables_found.Length() > 0 ? variables_found[0] : NULL);

    if (variable_symbol)
    {
        if (variable_symbol -> IsLocal()) // a local variable
        {
            if (where_found != stack)
            {
                TypeSymbol *type = stack -> Type();

                if (! variable_symbol -> ACC_FINAL())
                {
                    MethodSymbol *method = variable_symbol -> owner -> MethodCast();

                    ReportSemError(SemanticError::INNER_CLASS_REFERENCE_TO_NON_FINAL_LOCAL_VARIABLE,
                                   identifier_token,
                                   identifier_token,
                                   type -> ContainingPackage() -> PackageName(),
                                   type -> ExternalName(),
                                   lex_stream -> Name(identifier_token),
                                   //
                                   // TODO: What if the method is a constructor ?
                                   //        if (method -> Identity() != control.init_symbol &&
                                   //            method -> Identity() != control.block_init_symbol &&
                                   //            method -> Identity() != control.clinit_symbol)
                                   //
                                   //
                                   method -> Name());
                }

                type -> FindOrInsertLocalShadow(variable_symbol);

                variable_symbol = stack -> symbol_table.FindVariableSymbol(name_symbol);
                if (! variable_symbol)
                    variable_symbol = type -> FindVariableSymbol(name_symbol);
assert(variable_symbol);
                where_found = stack;
            }
        }
        else if (variable_symbol -> owner != where_found -> Type())  // is symbol an inherited field?
        {
            TypeSymbol *type = (TypeSymbol *) variable_symbol -> owner;

            if (variable_symbol -> IsSynthetic())
            {
                ReportSemError(SemanticError::SYNTHETIC_VARIABLE_ACCESS,
                               identifier_token,
                               identifier_token,
                               variable_symbol -> Name(),
                               type -> ContainingPackage() -> PackageName(),
                               type -> ExternalName());
            }
            else
            {
                for (SemanticEnvironment *env = where_found -> previous; env; env = env -> previous)
                {
                    Tuple<VariableSymbol *> others(2);
                    SemanticEnvironment *found_other;
                    SearchForVariableInEnvironment(others, found_other, env, name_symbol, identifier_token);

                    int i;
                    for (i = 0; i < others.Length();  i++)
                    {
                        if (others[i] != variable_symbol)
                        {
                            MethodSymbol *method = others[i] -> owner -> MethodCast();

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

                    if (i < others.Length()) // as soon as we find an error, bail out...
                        break;
                }
            }
        }
    }

    for (int i = 1; i < variables_found.Length(); i++)
    {
        ReportSemError(SemanticError::AMBIGUOUS_NAME,
                       identifier_token,
                       identifier_token,
                       variable_symbol -> Name(),
                       variable_symbol -> owner -> TypeCast() -> ContainingPackage() -> PackageName(),
                       variable_symbol -> owner -> TypeCast() -> ExternalName(),
                       variables_found[i] -> owner -> TypeCast() -> ContainingPackage() -> PackageName(),
                       variables_found[i] -> owner -> TypeCast() -> ExternalName());
    }

    return variable_symbol;
}


VariableSymbol *Semantic::FindInstance(TypeSymbol *base_type, TypeSymbol *environment_type)
{
    for (int i = 0; i < base_type -> NumEnclosingInstances(); i++)
    {
        VariableSymbol *variable = base_type -> EnclosingInstance(i);
        if (variable -> Type() -> IsSubclass(environment_type))
            return variable;
    }

    AstClassDeclaration *class_declaration = base_type -> declaration -> ClassDeclarationCast();
    AstClassInstanceCreationExpression *class_creation = base_type -> declaration -> ClassInstanceCreationExpressionCast();
assert(class_declaration || class_creation);
    AstClassBody *class_body = (class_declaration ? class_declaration -> class_body : class_creation -> class_body_opt);

    LexStream::TokenIndex loc = class_body -> left_brace_token;
    AstBlock *this_block = class_body -> this_block;
    if (! this_block)
    {
        this_block = compilation_unit -> ast_pool -> GenBlock();
        this_block -> left_brace_token  = loc;
        this_block -> right_brace_token = loc;

        this_block -> is_reachable = true;
        this_block -> can_complete_normally = true;

        class_body -> this_block = this_block;
    }

    int k = base_type -> NumEnclosingInstances();
    for (TypeSymbol *type = base_type -> EnclosingInstance(k - 1) -> Type(); type; type = type -> ContainingType(), k++)
    {
        AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(loc);
        simple_name -> symbol = base_type -> EnclosingInstance(k - 1);

        AstFieldAccess *field_access = compilation_unit -> ast_pool -> GenFieldAccess();
        field_access -> base = simple_name;
        field_access -> dot_token = loc;
        field_access -> identifier_token = loc;
        field_access -> symbol = type -> FindThis(0);

        AstMethodInvocation *rhs      = compilation_unit -> ast_pool -> GenMethodInvocation();
        rhs -> method                  = field_access;
        rhs -> left_parenthesis_token  = loc;
        rhs -> right_parenthesis_token = loc;
        rhs -> symbol                  = TypeSymbol::GetReadAccessMethod((VariableSymbol *) field_access -> symbol);

        AstSimpleName *lhs = compilation_unit -> ast_pool -> GenSimpleName(loc);
        VariableSymbol *variable = base_type -> FindThis(k);
        lhs -> symbol = (variable ? variable : base_type -> InsertThis(k));

        AstAssignmentExpression *assign = compilation_unit -> ast_pool
                                                            -> GenAssignmentExpression(AstAssignmentExpression::EQUAL, loc);
        assign -> left_hand_side = lhs;
        assign -> expression     = rhs;
        assign -> symbol         = lhs -> Type();

        AstExpressionStatement *stmt = compilation_unit -> ast_pool -> GenExpressionStatement();
        stmt -> expression          = assign;
        stmt -> semicolon_token_opt = loc;
        stmt -> is_reachable = true;
        stmt -> can_complete_normally = true;

        this_block -> AddStatement(stmt);

        if (lhs -> Type() -> IsSubclass(environment_type))
            break;
    }

    return base_type -> EnclosingInstance(k);
}


AstExpression *Semantic::CreateAccessToType(Ast *source, TypeSymbol *environment_type)
{
    TypeSymbol *this_type = ThisType();

    LexStream::TokenIndex tok;

    AstSimpleName *simple_name = source -> SimpleNameCast();
    AstFieldAccess *field_access = source -> FieldAccessCast();
    AstSuperCall *super_call = source -> SuperCallCast();
    AstThisCall *this_call = source -> ThisCallCast();
    AstClassInstanceCreationExpression *class_creation = source -> ClassInstanceCreationExpressionCast();

    if (simple_name)
         tok = simple_name -> identifier_token;
    else if (class_creation)
         tok = class_creation -> new_token;
    else if (super_call)
         tok = super_call -> super_token;
    else if (this_call)
         tok = this_call -> this_token;
    else if (field_access)
         tok = field_access -> dot_token;
    else assert(0);

    AstExpression *resolution;

    if (! this_type -> CanAccess(environment_type))
    {
        ReportSemError(SemanticError::ENCLOSING_INSTANCE_NOT_ACCESSIBLE,
                       (field_access ? field_access -> base -> LeftToken() : tok),
                       (field_access ? field_access -> base -> RightToken() : tok),
                       environment_type -> ContainingPackage() -> PackageName(),
                       environment_type -> ExternalName());

        resolution = compilation_unit -> ast_pool -> GenSimpleName(tok);
        resolution -> symbol = control.no_type;
    }
    else if (ExplicitConstructorInvocation() && ExplicitConstructorInvocation() -> SuperCallCast())
    {
        VariableSymbol *variable = LocalSymbolTable().FindVariableSymbol(control.this0_name_symbol);
        if (variable)
        {
            resolution = compilation_unit -> ast_pool -> GenSimpleName(tok);
            resolution -> symbol = variable;
            TypeSymbol *containing_type = this_type -> ContainingType();
            if (! containing_type -> IsSubclass(environment_type))
            {
                variable = FindInstance(containing_type, environment_type);

                AstFieldAccess *field_access = compilation_unit -> ast_pool -> GenFieldAccess();
                field_access -> base = resolution;
                field_access -> dot_token = field_access -> dot_token;
                field_access -> identifier_token = field_access -> dot_token;
                field_access -> symbol = variable;

                AstMethodInvocation *method_call      = compilation_unit -> ast_pool -> GenMethodInvocation();
                method_call -> method                  = field_access;
                method_call -> left_parenthesis_token  = field_access -> dot_token;
                method_call -> right_parenthesis_token = field_access -> dot_token;
                method_call -> symbol                  = TypeSymbol::GetReadAccessMethod(variable);

                resolution = method_call;
            }
        }
        else
        {
assert(this_type -> ACC_STATIC());
            resolution = compilation_unit -> ast_pool -> GenThisExpression(tok);
            resolution -> symbol = this_type;
        }
    }
    else if (this_type -> IsSubclass(environment_type))
    {
        resolution = compilation_unit -> ast_pool -> GenThisExpression(tok);
        resolution -> symbol = this_type;
    }
    else
    {
        resolution = compilation_unit -> ast_pool -> GenSimpleName(tok);
        resolution -> symbol = FindInstance(this_type, environment_type);
    }

    return ((resolution -> symbol == control.no_type) || (resolution -> Type() == environment_type)
                                                       ? resolution
                                                       : ConvertToType(resolution, environment_type));
}


void Semantic::CreateAccessToScopedVariable(AstSimpleName *simple_name, TypeSymbol *environment_type)
{
assert(environment_type -> IsOwner(ThisType()));
    VariableSymbol *variable_symbol = (VariableSymbol *) simple_name -> symbol;

    AstExpression *access_expression;
    if (variable_symbol -> ACC_STATIC())
    {
        access_expression = compilation_unit -> ast_pool -> GenSimpleName(simple_name -> identifier_token);
        access_expression -> symbol = environment_type;
    }
    else access_expression = CreateAccessToType(simple_name, environment_type);

    if (access_expression -> symbol != control.no_type)
    {
        AstFieldAccess *field_access = compilation_unit -> ast_pool -> GenFieldAccess();
        field_access -> base = access_expression;
        field_access -> dot_token = simple_name -> identifier_token;
        field_access -> identifier_token = simple_name -> identifier_token;
        field_access -> symbol = variable_symbol;

        //
        // TODO: we have filed a query to Sun regarding the necessity of this check!
        //
        // SimpleNameAccessCheck(simple_name, variable_symbol -> owner -> TypeCast(), variable_symbol);
        //

        if (variable_symbol -> ACC_PRIVATE())
        {
            AstMethodInvocation *method_call       = compilation_unit -> ast_pool -> GenMethodInvocation();
            method_call -> method                  = field_access;
            method_call -> left_parenthesis_token  = simple_name -> identifier_token;
            method_call -> right_parenthesis_token = simple_name -> identifier_token;
            method_call -> symbol                  = TypeSymbol::GetReadAccessMethod(variable_symbol);

            simple_name -> resolution_opt = method_call;
        }
        else simple_name -> resolution_opt = field_access;
    }

    return;
}


void Semantic::CreateAccessToScopedMethod(AstMethodInvocation *method_call, TypeSymbol *environment_type)
{
assert(environment_type -> IsOwner(ThisType()));
    MethodSymbol *method = (MethodSymbol *) method_call -> symbol;
    AstSimpleName *simple_name = (AstSimpleName *) method_call -> method;
assert(simple_name -> SimpleNameCast());

    AstExpression *access_expression;
    if (method -> ACC_STATIC())
    {
        access_expression = compilation_unit -> ast_pool -> GenSimpleName(simple_name -> identifier_token);
        access_expression -> symbol = environment_type;
    }
    else access_expression = CreateAccessToType(simple_name, environment_type);

    if (access_expression -> symbol != control.no_type)
    {
        //
        // TODO: we have filed a query to Sun regarding the necessity of this check!
        //
        // SimpleNameAccessCheck(simple_name, method -> containing_type, method);
        //

        simple_name -> resolution_opt = access_expression;
        if (method -> ACC_PRIVATE())
            method_call -> symbol = TypeSymbol::GetReadAccessMethod(method);
    }

    return;
}


void Semantic::ProcessSimpleName(Ast *expr)
{
    TypeSymbol *this_type = ThisType();

    AstSimpleName *simple_name = (AstSimpleName *) expr;
    SemanticEnvironment *where_found;
    VariableSymbol *variable_symbol = FindVariableInEnvironment(where_found, state_stack.Top(), simple_name -> identifier_token);
    if (variable_symbol)
    {
        simple_name -> symbol = variable_symbol;

        if (! variable_symbol -> IsTyped())
            variable_symbol -> ProcessVariableSignature((Semantic *) this, simple_name -> identifier_token);

        //
        // A variable_symbol FINAL must have an initial value.
        //
        if (variable_symbol -> ACC_FINAL())
        {
            if (variable_symbol -> IsDeclarationComplete())
                simple_name -> value = variable_symbol -> initial_value;
            else if (variable_symbol -> declarator)
            {
                AstVariableDeclarator *declarator = variable_symbol -> declarator -> VariableDeclaratorCast();
                //
                // If the variable declarator in question exists and its computation is not
                // pending (to avoid looping) and it has a simple expression initializer.
                //
                if (declarator &&
                    (! declarator -> pending) && 
                    declarator -> variable_initializer_opt &&
                    (! declarator -> variable_initializer_opt -> ArrayInitializerCast()))
                {
                    TypeSymbol *type = (TypeSymbol *) variable_symbol -> owner;
                    Semantic *sem = type -> semantic_environment -> sem;
                    simple_name -> value = sem -> ComputeFinalValue(declarator);
                }
            }
        }

        //
        // If the variable belongs to an outer type, add the proper
        // pointer dereferences (and method access in the case of a
        // private variable) necessary to get to it.
        //
        if (where_found != state_stack.Top())
            CreateAccessToScopedVariable(simple_name, where_found -> Type());

        // 
        // CreateAccessToScopedVariable did not detect an error?
        // 
        if (simple_name -> symbol != control.no_type)
        {
            if (StaticRegion())
            {
                if (! (variable_symbol -> IsLocal() || variable_symbol -> ACC_STATIC()))
                {
                    ReportSemError(SemanticError::NAME_NOT_CLASS_VARIABLE,
                                   simple_name -> identifier_token,
                                   simple_name -> identifier_token,
                                   lex_stream -> Name(simple_name -> identifier_token));
                }
                else if (! variable_symbol -> IsDeclarationComplete())
                {
                    ReportSemError(SemanticError::NAME_NOT_YET_AVAILABLE,
                                   simple_name -> identifier_token,
                                   simple_name -> identifier_token,
                                   lex_stream -> Name(simple_name -> identifier_token));
                }
            }
            else if (! variable_symbol -> ACC_STATIC()) // an instance variable?
            {
                TypeSymbol *containing_type = variable_symbol -> owner -> TypeCast(); // an instance field member ?

                if (containing_type)
                {
                    if (containing_type == this_type && (! variable_symbol -> IsDeclarationComplete()))
                    {
                        ReportSemError(SemanticError::NAME_NOT_YET_AVAILABLE,
                                       simple_name -> identifier_token,
                                       simple_name -> identifier_token,
                                       lex_stream -> Name(simple_name -> identifier_token));
                    }
                    else if (ExplicitConstructorInvocation() && where_found == state_stack.Top())
                    {
                        //
                        // If the variable in question is an instance variable that is
                        // declared in this_type (this_type is definitely a class) or
                        // one of its super classes, then we have an error:
                        //
                        ReportSemError(SemanticError::INSTANCE_VARIABLE_IN_EXPLICIT_CONSTRUCTOR_INVOCATION,
                                       simple_name -> identifier_token,
                                       simple_name -> identifier_token,
                                       lex_stream -> Name(simple_name -> identifier_token),
                                       containing_type -> Name());
                    }
                }
            }
        }
    }
    else
    {
        //
        // We make a little effort to issue a better error message if we can identify
        // the name in question as the name of a method in the local type.
        //
        NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(simple_name -> identifier_token);

        MethodShadowSymbol *method_shadow;
        MethodSymbol *method;

        for (method_shadow = this_type -> expanded_method_table -> FindMethodShadowSymbol(name_symbol);
             method_shadow; method_shadow = method_shadow -> next_method)
        {
            method = method_shadow -> method_symbol;
            TypeSymbol *containing_type = method -> containing_type;

            if (method -> NumFormalParameters((Semantic *) this, simple_name -> identifier_token) == 0)
                break;
        }
                                                   
        if (method_shadow)
        {
             ReportSemError(SemanticError::METHOD_NOT_FIELD,
                            simple_name -> identifier_token,
                            simple_name -> identifier_token,
                            lex_stream -> Name(simple_name -> identifier_token),
                            method -> containing_type -> ContainingPackage() -> PackageName(),
                            method -> containing_type -> ExternalName());
        }
        else if (FindType(simple_name -> identifier_token))
        {
             ReportSemError(SemanticError::TYPE_NOT_FIELD,
                            simple_name -> identifier_token,
                            simple_name -> identifier_token,
                            lex_stream -> Name(simple_name -> identifier_token));
        }
        else
        {
            VariableSymbol *variable = FindMisspelledVariableName(this_type, simple_name -> identifier_token);
            if (variable)
                 ReportSemError(SemanticError::FIELD_NAME_MISSPELLED,
                                simple_name -> identifier_token,
                                simple_name -> identifier_token,
                                name_symbol -> Name(),
                                this_type -> ContainingPackage() -> PackageName(),
                                this_type -> ExternalName(),
                                variable -> Name());
            else ReportSemError(SemanticError::NAME_NOT_FOUND,
                                simple_name -> identifier_token,
                                simple_name -> identifier_token,
                                lex_stream -> Name(simple_name -> identifier_token));
        }
        simple_name -> symbol = control.no_type;
    }

    return;
}


void Semantic::TypeAccessCheck(Ast *ast, TypeSymbol *type)
{
    //
    // Unless we are processing the body of a type do not do type checking.
    // (This method may be invoked, for example, when FindFirstType invokes ProcessPackageOrType)
    //
    if (state_stack.Size() > 0)
    {
        TypeSymbol *this_type = ThisType();

        //
        // Type checking is necessary only for two types that are not enclosed within
        // the same outermost type. Note that if we are trying to access an inner type
        // T1.T2...Tn from this type, TypeAccessCheck is expected to be invoked first
        // for T1, then T1.T2, ... and finally for T1.T2...Tn, in turn. When invoked
        // for T1.T2, for example, this function only checks whether or not T1.T2
        // is accessible from "this" type. It does not recheck whether or not T1 is
        // accessible.
        //
        if (this_type -> outermost_type != type -> outermost_type)
        {
            if (type -> ACC_PRIVATE())
                 ReportTypeInaccessible(ast, type);
            else if (type -> ACC_PROTECTED())
            {
                //
                // TODO: we have filed a query to Sun regarding which test is required here!
                //
                // if (! (type -> ContainingPackage() == this_package || this_type -> IsSubclass(type)))
                //
                if (! (type -> ContainingPackage() == this_package || this_type -> HasProtectedAccessTo(type)))
                    ReportTypeInaccessible(ast, type);
            }
            else if (! (type -> ACC_PUBLIC() || type -> ContainingPackage() == this_package))
                 ReportTypeInaccessible(ast, type);
        }
    }

    return;
}


void Semantic::TypeNestAccessCheck(AstExpression *name)
{
    AstSimpleName *simple_name = name -> SimpleNameCast();
    AstFieldAccess *field_access = name -> FieldAccessCast();
assert(simple_name || field_access);
    if (field_access)
        TypeNestAccessCheck(field_access -> base);

    TypeSymbol *type = (simple_name ? simple_name -> Type() : field_access -> Type());
    if (type)
        TypeAccessCheck(name, type);

    return;
}


void Semantic::ConstructorAccessCheck(AstClassInstanceCreationExpression *class_creation, MethodSymbol *constructor)
{
    TypeSymbol *this_type = ThisType();
    TypeSymbol *containing_type = constructor -> containing_type;

    if (this_type -> outermost_type != containing_type -> outermost_type)
    {
        if (constructor -> ACC_PRIVATE())
        {
            ReportSemError(SemanticError::PRIVATE_CONSTRUCTOR_NOT_ACCESSIBLE,
                           class_creation -> class_type -> LeftToken(),
                           class_creation -> right_parenthesis_token,
                           constructor -> Header(),
                           containing_type -> ContainingPackage() -> PackageName(),
                           containing_type -> ExternalName());
        }
        else if (! class_creation -> symbol -> TypeCast() -> Anonymous())
        {
            if (constructor -> ACC_PROTECTED())
            {
                //
                // TODO: we need to file a query to Sun regarding which test is required here!
                // According to the rules 6.6.2 in the JLS, access to a protected constructor
                // that is not contained in the same package is only valid through a "super(...)" call.
                // However, javac seems to have relaxed this restriction to allow subclass access...
                //
                //
                // TODO: we have filed a query to Sun regarding which test is required here!
                //
                // if (! (containing_type -> ContainingPackage() == this_package || this_type -> IsSubclass(containing_type)))
                //
                if (! (containing_type -> ContainingPackage() == this_package || this_type -> HasProtectedAccessTo(containing_type)))
                {
                    ReportSemError(SemanticError::PROTECTED_CONSTRUCTOR_NOT_ACCESSIBLE,
                                   class_creation -> class_type -> LeftToken(),
                                   class_creation -> right_parenthesis_token,
                                   constructor -> Header(),
                                   containing_type -> ContainingPackage() -> PackageName(),
                                   containing_type -> ExternalName());
                }
            }
            else if (! (constructor -> ACC_PUBLIC() || containing_type -> ContainingPackage() == this_package))
            {
                ReportSemError(SemanticError::DEFAULT_CONSTRUCTOR_NOT_ACCESSIBLE,
                               class_creation -> class_type -> LeftToken(),
                               class_creation -> right_parenthesis_token,
                               constructor -> Header(),
                               containing_type -> ContainingPackage() -> PackageName(),
                               containing_type -> ExternalName());
            }
        }
    }

    return;
}


void Semantic::MemberAccessCheck(AstFieldAccess *field_access, TypeSymbol *base_type, TypeSymbol *containing_type, Symbol *symbol)
{
    TypeSymbol *this_type = ThisType();

    VariableSymbol *variable_symbol = symbol -> VariableCast();
    MethodSymbol *method_symbol = symbol -> MethodCast();
assert(variable_symbol || method_symbol);
    AccessFlags *flags = (variable_symbol ? (AccessFlags *) variable_symbol : (AccessFlags *) method_symbol);

    AstExpression *base = field_access -> base;
    if (! (containing_type -> ACC_PUBLIC() || base_type -> ContainingPackage() == containing_type -> ContainingPackage()))
        ReportTypeInaccessible(base, containing_type);

    if (this_type -> outermost_type != containing_type -> outermost_type)
    {
        if (flags -> ACC_PRIVATE())
        {
            ReportSemError((variable_symbol ? SemanticError::PRIVATE_FIELD_NOT_ACCESSIBLE
                                            : SemanticError::PRIVATE_METHOD_NOT_ACCESSIBLE),
                           field_access -> identifier_token,
                           field_access -> identifier_token,
                           lex_stream -> Name(field_access -> identifier_token),
                           containing_type -> ContainingPackage() -> PackageName(),
                           containing_type -> ExternalName());
        }
        else if (flags -> ACC_PROTECTED())
        {
            //
            // TODO: we have filed a query to Sun regarding which test is required here!
            //       there also appears to be a mistake in the Language Spec in section
            //       6.6.2 re. access to protected members. The phrase "Q is S or a subclass of S"
            //       should have been "Q is S or a superclass of S".
            //       
            // if (! (containing_type -> ContainingPackage() == this_package || this_type -> IsSubclass(containing_type)))
            //
            if (! (base -> SuperExpressionCast() ||
                   containing_type -> ContainingPackage() == this_package ||
                   (this_type -> HasProtectedAccessTo(containing_type) && 
                    (base_type -> IsSubclass(this_type) || base_type -> IsOwner(this_type)))))
            {
                ReportSemError((variable_symbol ? SemanticError::PROTECTED_FIELD_NOT_ACCESSIBLE
                                                : SemanticError::PROTECTED_METHOD_NOT_ACCESSIBLE),
                               field_access -> identifier_token,
                               field_access -> identifier_token,
                               lex_stream -> Name(field_access -> identifier_token),
                               containing_type -> ContainingPackage() -> PackageName(),
                               containing_type -> ExternalName());
            }
        }
        else if (! (flags -> ACC_PUBLIC() || containing_type -> ContainingPackage() == this_package))
        {
            ReportSemError((variable_symbol ? SemanticError::DEFAULT_FIELD_NOT_ACCESSIBLE
                                            : SemanticError::DEFAULT_METHOD_NOT_ACCESSIBLE),
                           field_access -> identifier_token,
                           field_access -> identifier_token,
                           lex_stream -> Name(field_access -> identifier_token),
                           containing_type -> ContainingPackage() -> PackageName(),
                           containing_type -> ExternalName());
        }
    }

    return;
}


void Semantic::SimpleNameAccessCheck(AstSimpleName *simple_name, TypeSymbol *containing_type, Symbol *symbol)
{
    TypeSymbol *this_type = ThisType();

    VariableSymbol *variable_symbol = symbol -> VariableCast();
    MethodSymbol *method_symbol = symbol -> MethodCast();
assert(variable_symbol || method_symbol);
    AccessFlags *flags = (variable_symbol ? (AccessFlags *) variable_symbol : (AccessFlags *) method_symbol);

    if (! (containing_type -> ACC_PUBLIC() || this_type -> ContainingPackage() == containing_type -> ContainingPackage()))
        ReportTypeInaccessible(simple_name, containing_type);

    if (this_type -> outermost_type != containing_type -> outermost_type)
    {
        if (flags -> ACC_PRIVATE())
        {
            ReportSemError((variable_symbol ? SemanticError::PRIVATE_FIELD_NOT_ACCESSIBLE
                                            : SemanticError::PRIVATE_METHOD_NOT_ACCESSIBLE),
                           simple_name -> identifier_token,
                           simple_name -> identifier_token,
                           lex_stream -> Name(simple_name -> identifier_token),
                           containing_type -> ContainingPackage() -> PackageName(),
                           containing_type -> ExternalName());
        }
        else if (flags -> ACC_PROTECTED())
        {
            if (! (containing_type -> ContainingPackage() == this_package || this_type -> IsSubclass(containing_type)))
            {
                ReportSemError((variable_symbol ? SemanticError::PROTECTED_FIELD_NOT_ACCESSIBLE
                                                : SemanticError::PROTECTED_METHOD_NOT_ACCESSIBLE),
                               simple_name -> identifier_token,
                               simple_name -> identifier_token,
                               lex_stream -> Name(simple_name -> identifier_token),
                               containing_type -> ContainingPackage() -> PackageName(),
                               containing_type -> ExternalName());
            }
        }
        else if (! (flags -> ACC_PUBLIC() || containing_type -> ContainingPackage() == this_package))
        {
            ReportSemError((variable_symbol ? SemanticError::DEFAULT_FIELD_NOT_ACCESSIBLE
                                            : SemanticError::DEFAULT_METHOD_NOT_ACCESSIBLE),
                           simple_name -> identifier_token,
                           simple_name -> identifier_token,
                           lex_stream -> Name(simple_name -> identifier_token),
                           containing_type -> ContainingPackage() -> PackageName(),
                           containing_type -> ExternalName());
        }
    }

    return;
}


void Semantic::FindVariableMember(TypeSymbol *type, AstFieldAccess *field_access)
{
    TypeSymbol *this_type = ThisType();

    //
    // This operation may throw NullPointerException
    //
    SymbolSet *exception_set = TryExceptionTableStack().Top();
    if (exception_set)
    {
        exception_set -> AddElement(control.RuntimeException());
        exception_set -> AddElement(control.Error());
    }
    
    if (type -> Bad())
    {
        //
        // If no error has been detected so far, report this as an error so that
        // we don't try to generate code later. On the other hand, if an error
        // had been detected prior to this, don't flood the user with spurious
        // messages.
        //
        if (NumErrors() == 0)
            ReportAccessedFieldNotFound(field_access, type);
        field_access -> symbol = control.no_type;
    }
    else if (type == control.null_type || type -> Primitive())
    {
        ReportSemError(SemanticError::TYPE_NOT_REFERENCE,
                       field_access -> base -> LeftToken(),
                       field_access -> base -> RightToken(),
                       type -> Name());
        field_access -> symbol = control.no_type;
    }
    else
    {
        TypeAccessCheck(field_access -> base, type);

        VariableSymbol *variable_symbol = FindVariableInType(type, field_access);
        if (variable_symbol)
        {
            //
            // If a variable is FINAL and initialized with a constant expression,
            // we substitute the expression here. JLS section 15.27, pp 381-382.
            //
            // TODO: Note that the JLS is a bit ambiguous and that a strict reading
            // of 15.27 would prohibit substitution of a final constant value here. 
            // However, javac seems to accept it and as the section on qualified name
            // only mentions "final" but not "static" and as it is not possible to derefence
            // a non-static final with a TypeName, we decided to relax the rules also.
            //
            if (variable_symbol -> ACC_FINAL() && field_access -> base -> IsName())
            {
                //
                // If the field declaration of the type has been completely processed,
                // simply retrieve the value. Otherwise, compute the value of the
                // initialization expression in question on the fly if the variable
                // in question is not in the same type. Recall that static variables 
                // must be processed in the textual order in which they appear in the
                // body of a type. Therefore, if the static initialization of a field
                // refers to another variable in the same type it must have appeared
                // before the current field declaration otherwise we will emit an error
                // message later...
                //
                if (variable_symbol -> IsDeclarationComplete())
                    field_access -> value = variable_symbol -> initial_value;
                else if (variable_symbol -> declarator)
                {
                    AstVariableDeclarator *declarator = variable_symbol -> declarator -> VariableDeclaratorCast();
                    //
                    // If the variable declarator in question exists and its computation is not
                    // pending (to avoid looping) and it has a simple expression initializer.
                    //
                    if (declarator && (! declarator -> pending) && 
                        declarator -> variable_initializer_opt &&
                        (! declarator -> variable_initializer_opt -> ArrayInitializerCast()))
                    {
                        TypeSymbol *variable_type = (TypeSymbol *) variable_symbol -> owner;
                        Semantic *sem = variable_type -> semantic_environment -> sem;
                        field_access -> value = sem -> ComputeFinalValue(declarator);
                    }
                }
            }

            TypeSymbol *containing_type = (TypeSymbol *) variable_symbol -> owner;
            if (variable_symbol -> ACC_PRIVATE() && // access to an private variable in an enclosing type ?
                this_type != containing_type && this_type -> outermost_type == containing_type -> outermost_type)
            {
                if (field_access -> IsConstant())
                    field_access -> symbol = variable_symbol;
                else
                {
                    AstFieldAccess *method_access = compilation_unit -> ast_pool -> GenFieldAccess();
                    method_access -> base = field_access -> base;  // TODO: WARNING: sharing of Ast subtree !!!
                    method_access -> dot_token = field_access -> identifier_token;
                    method_access -> identifier_token = field_access -> identifier_token;
                    method_access -> symbol = variable_symbol; // the variable in question

                    AstMethodInvocation *p      = compilation_unit -> ast_pool -> GenMethodInvocation();
                    p -> method                  = method_access;
                    p -> left_parenthesis_token  = field_access -> identifier_token;
                    p -> right_parenthesis_token = field_access -> identifier_token;
                    p -> symbol                  = TypeSymbol::GetReadAccessMethod(variable_symbol);

                    field_access -> resolution_opt = p;
                    field_access -> symbol = p -> symbol;
                }
            }
            else
            {
                field_access -> symbol = variable_symbol;
                MemberAccessCheck(field_access, type, containing_type, variable_symbol);
            }
        }
        else
        {
            TypeSymbol *inner_type;
            if (inner_type = FindNestedType(type, field_access -> identifier_token))
                 ReportSemError(SemanticError::FIELD_IS_TYPE,
                                field_access -> identifier_token,
                                field_access -> identifier_token,
                                lex_stream -> Name(field_access -> identifier_token));
            else ReportAccessedFieldNotFound(field_access, type);

            field_access -> symbol = control.no_type;
        }
    }

    return;
}

//
// NOTE that method names are not processed here but by the function
// ProcessMethodName.
//
void Semantic::ProcessAmbiguousName(Ast *name)
{
    TypeSymbol *this_type = ThisType();

    AstSimpleName *simple_name;

    //
    // ...If the ambiguous name is a simple name,...
    //
    if (simple_name = name -> SimpleNameCast())
    {
        TypeSymbol *type;
        //
        // ... If the Identifier appears within the scope (6.3) if a local variable declaration (14.3)
        // or parameter declaration (8.4.1, 8.6.1, 14.18) with that name, then the ambiguous name is
        // reclassified as an ExpressionName...
        //
        // ...Otherwise, consider the class or interface C within whose declaration the Identifier occurs.
        // If C has one or more fields with that name, which may be either declared within it or inherited,
        // then the Ambiguous name is reclassified as an ExpressionName....
        //
        SemanticEnvironment *where_found;
        VariableSymbol *variable_symbol = FindVariableInEnvironment(where_found, state_stack.Top(), simple_name -> identifier_token);
        if (variable_symbol)
        {
            //
            // A variable_symbol that is FINAL may have an initial value.
            // If variable_symbol is not final then its initial value is NULL.
            //
            simple_name -> value = variable_symbol -> initial_value;
            simple_name -> symbol = variable_symbol;

            //
            // If the variable belongs to an outer type, add the proper
            // pointer dereferences (and method access in the case of a
            // private variable) necessary to  get to it.
            //
            if (where_found != state_stack.Top())
                CreateAccessToScopedVariable(simple_name, where_found -> Type());

            if (StaticRegion())
            {
                if (! (variable_symbol -> IsLocal() || variable_symbol -> ACC_STATIC()))
                {
                    ReportSemError(SemanticError::NAME_NOT_CLASS_VARIABLE,
                                   simple_name -> identifier_token,
                                   simple_name -> identifier_token,
                                   lex_stream -> Name(simple_name -> identifier_token));
                }
                else if (! variable_symbol -> IsDeclarationComplete())
                {
                    ReportSemError(SemanticError::NAME_NOT_YET_AVAILABLE,
                                   simple_name -> identifier_token,
                                   simple_name -> identifier_token,
                                   lex_stream -> Name(simple_name -> identifier_token));
                }
            }

            if (ExplicitConstructorInvocation() && (! variable_symbol -> ACC_STATIC()))
            {
                //
                // If the variable in question is an instance variable
                // that is declared in this_type (this_type is definitely
                // a class) or one of its super classes, then we have an error -> 
                //
                TypeSymbol *type = variable_symbol -> owner -> TypeCast();
                if (type)
                {
                    ReportSemError(SemanticError::INSTANCE_VARIABLE_IN_EXPLICIT_CONSTRUCTOR_INVOCATION,
                                   simple_name -> identifier_token,
                                   simple_name -> identifier_token,
                                   lex_stream -> Name(simple_name -> identifier_token),
                                   type -> Name());
                }
            }
        }

        //
        // ...Otherwise, if a type of that name is declared in the compilation unit (7.3) containing
        // the Identifier, either by a single-type-import declaration (7.5.1) or by a class or interface
        // type declaration (7.6), then the Ambiguous name is reclassified as a TypeName...
        //
        // ...Otherwise, if a type of that name is declared in another compilation unit (7.3) of the
        // package (7.1) of the compilation unit containing the Identifier, then the Ambiguous Name
        // is reclassified as a TypeName...
        //
        // ...Otherwise, if a type of that name is declared by exactly one type-import-on-demand declaration
        // (7.5.2) of the compilation unit containing the Identifier, then the AmbiguousName is reclassified
        // as a TypeName
        //
        // ...Otherwise, if a type of that name is declared by more than one type-import-on-demand declaration
        // of the compilation unit containing the Identifier, then a compile-time error results.
        //
        else if (type = FindType(simple_name -> identifier_token))
             simple_name -> symbol = type;
        //
        // ...Otherwise, the Ambiguous name is reclassified as a PackageName. A later step determines
        // whether or not a package of that name actually exists.
        //
        else
        {
            NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(simple_name -> identifier_token);
            PackageSymbol *package = control.external_table.FindPackageSymbol(name_symbol);
            if (package)
                simple_name -> symbol = package;
            else
            {
                package = control.external_table.InsertPackageSymbol(name_symbol, NULL);
                control.FindPathsToDirectory(package);
                simple_name -> symbol = package;
            }
        }
    }
    //
    // ...If the ambiguous name is a qualified name,...
    //
    else
    {
        AstFieldAccess *field_access = (AstFieldAccess *) name;
assert(name -> FieldAccessCast());
        TypeSymbol *type = NULL;

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

            AstTypeExpression *base = (AstTypeExpression *) field_access -> base;

            AstArrayType *array_type = base -> type -> ArrayTypeCast();
            if (array_type)
            {
                AstPrimitiveType *primitive_type = array_type -> type -> PrimitiveTypeCast();
                TypeSymbol *unit = (primitive_type ? FindPrimitiveType(primitive_type) : MustFindType(array_type -> type));
                type = unit -> GetArrayType((Semantic *) this, array_type -> NumBrackets());
            }
            else
            {
                AstPrimitiveType *primitive_type = base -> type -> PrimitiveTypeCast();
                type = (primitive_type ? FindPrimitiveType(primitive_type) : MustFindType(base -> type));
            }

            TypeSymbol *outermost_type = this_type -> outermost_type;

            if (type -> Primitive())
            {
                if (type == control.int_type)
                     type = control.Integer();
                else if (type == control.double_type)
                     type = control.Double();
                else if (type == control.char_type)
                     type = control.Character();
                else if (type == control.long_type)
                     type = control.Long();
                else if (type == control.float_type)
                     type = control.Float();
                else if (type == control.byte_type)
                     type = control.Byte();
                else if (type == control.short_type)
                     type = control.Short();
                else if (type == control.boolean_type)
                     type = control.Boolean();
                else // (type == control.void_type)
                     type = control.Void();
                base -> symbol = type;
                field_access -> symbol = type -> FindVariableSymbol(control.type_name_symbol);
assert(field_access -> symbol);
            }
            else
            {
                base -> symbol = type;

                if (outermost_type -> ACC_INTERFACE())
                {
                    TypeSymbol *class_literal_type = outermost_type -> FindOrInsertClassLiteralClass(field_access -> identifier_token);
                    AddDependence(this_type, class_literal_type, field_access -> identifier_token);

                    AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(field_access -> identifier_token);
                    simple_name -> symbol = class_literal_type;

                    AstFieldAccess *method_access = compilation_unit -> ast_pool -> GenFieldAccess();
                    method_access -> base = simple_name;
                    method_access -> dot_token = field_access -> identifier_token;
                    method_access -> identifier_token = field_access -> identifier_token;

                    AstStringLiteral *string_literal = compilation_unit -> ast_pool -> GenStringLiteral(field_access -> identifier_token);
                    string_literal -> value = type -> FindOrInsertClassLiteralName(control);
                    string_literal -> symbol = control.String();

                    AstMethodInvocation *method_call       = compilation_unit -> ast_pool -> GenMethodInvocation();
                    method_call -> method                  = method_access;
                    method_call -> left_parenthesis_token  = field_access -> identifier_token;
                    method_call -> AddArgument(string_literal);
                    method_call -> right_parenthesis_token = field_access -> identifier_token;
                    method_call -> symbol                  = class_literal_type -> ClassLiteralMethod();

                    field_access -> resolution_opt = method_call;
                    field_access -> symbol = (method_call -> symbol ? method_call -> symbol : control.no_type);
                }
                else
                {
                    AddDependence(this_type, control.Class(), field_access -> identifier_token);

                    VariableSymbol *variable_symbol = outermost_type -> FindOrInsertClassLiteral(type);
                    if (this_type == outermost_type)
                    {
                        AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(field_access -> identifier_token);
                        simple_name -> symbol = variable_symbol;

                        field_access -> symbol = variable_symbol;
                        field_access -> resolution_opt = simple_name;
                    }
                    else
                    {
                        AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(field_access -> identifier_token);
                        simple_name -> symbol = outermost_type;

                        AstFieldAccess *method_access = compilation_unit -> ast_pool -> GenFieldAccess();
                        method_access -> base = simple_name;
                        method_access -> dot_token = field_access -> identifier_token;
                        method_access -> identifier_token = field_access -> identifier_token;
                        method_access -> symbol = variable_symbol; // the variable in question

                        AstMethodInvocation *method_call       = compilation_unit -> ast_pool -> GenMethodInvocation();
                        method_call -> method                  = method_access;
                        method_call -> left_parenthesis_token  = field_access -> identifier_token;
                        method_call -> right_parenthesis_token = field_access -> identifier_token;
                        method_call -> symbol                  = TypeSymbol::GetWriteAccessMethod(variable_symbol);

                        field_access -> resolution_opt = method_call;
                        field_access -> symbol = TypeSymbol::GetReadAccessMethod(variable_symbol);
                    }
                }
            }
        }
        else
        {
            AstExpression* base = field_access -> base;
            AstFieldAccess *sub_field_access = base -> FieldAccessCast();
            simple_name = base -> SimpleNameCast();

            //
            // ...First, classify the name or expression to the left of the '.'...
            //
            if (simple_name || sub_field_access)
                 ProcessAmbiguousName(base);
            else ProcessExpression(base);

            if (base -> symbol == control.no_type)
            {
                field_access -> symbol = control.no_type;
                return;
            }

            wchar_t *identifier_name = lex_stream -> Name(field_access -> identifier_token);
            PackageSymbol *package;

            Symbol *symbol = base -> symbol;

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

                TypeSymbol *enclosing_type = symbol -> TypeCast();
                if (enclosing_type == control.no_type)
                    field_access -> symbol = control.no_type;
                else
                {
                    if (! enclosing_type)
                    {
                        ReportSemError(SemanticError::NOT_A_TYPE,
                                       field_access -> base -> LeftToken(),
                                       field_access -> base -> RightToken());
                        field_access -> symbol = control.no_type;
                    }
                    else if (enclosing_type -> ACC_INTERFACE())
                    {
                        ReportSemError(SemanticError::NOT_A_CLASS,
                                       field_access -> base -> LeftToken(),
                                       field_access -> base -> RightToken(),
                                       enclosing_type -> ContainingPackage() -> PackageName(),
                                       enclosing_type -> ExternalName());
                        field_access -> symbol = control.no_type;
                    }
                    else
                    {
                        if (! (this_type -> IsNestedIn(enclosing_type) && this_type -> CanAccess(enclosing_type)))
                        {
                            if (this_type == enclosing_type && field_access -> IsThisAccess())
                            {
                                ReportSemError(SemanticError::MISPLACED_THIS_EXPRESSION,
                                               field_access -> LeftToken(),
                                               field_access -> RightToken());
                            }
                            else
                            {
                                ReportSemError(SemanticError::ILLEGAL_THIS_FIELD_ACCESS,
                                               field_access -> LeftToken(),
                                               field_access -> RightToken(),
                                               enclosing_type -> ContainingPackage() -> PackageName(),
                                               enclosing_type -> ExternalName(),
                                               this_type -> ContainingPackage() -> PackageName(),
                                               this_type -> ExternalName());
                            }

                            field_access -> symbol = control.no_type;
                        }
                        else
                        {
                            //
                            // Note that in the case of a Super access, there will be further resolution later.
                            //
                            field_access -> resolution_opt = CreateAccessToType(field_access, enclosing_type);
                            field_access -> symbol = field_access -> resolution_opt -> symbol;
                        }
                    }
                }
            }
            else if (package = symbol -> PackageCast())
            {
                //
                // ... If there is a package whose name is the name to the left of the '.' and that package
                // contains a declaration of a type whose name is the same as the Identifier, then the
                // AmbiguousName is reclassified as a TypeName...
                //
                NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token);
                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)
                    {
                        type = ReadType(file_symbol, package, name_symbol, field_access -> identifier_token);
                        field_access -> symbol = type;
                    }
                    //
                    // ... Otherwise, this AmbiguousName is reclassified as a PackageName. A later step determines
                    // whether or not a package of that name actually exists...
                    //
                    else
                    {
                        PackageSymbol *subpackage = package -> FindPackageSymbol(name_symbol);
                        if (! subpackage) // A new package ?
                        {
                            subpackage = package -> InsertPackageSymbol(name_symbol);
                            control.FindPathsToDirectory(subpackage);
                        }
                        field_access -> symbol = subpackage;
                    }
                }
            }
            else if (sub_field_access && sub_field_access -> IsSuperAccess())
            {
                if (sub_field_access -> Type() == control.no_type)
                    field_access -> symbol = control.no_type;
                else if (sub_field_access -> Type() == control.Object())
                {
                    ReportSemError(SemanticError::OBJECT_HAS_NO_SUPER_TYPE,
                                   sub_field_access -> LeftToken(),
                                   sub_field_access -> RightToken(),
                                   sub_field_access -> Type() -> ContainingPackage() -> PackageName(),
                                   sub_field_access -> Type() -> ExternalName());
                    field_access -> symbol = control.no_type;
                }
                else
                {
                    type = sub_field_access -> Type() -> super;
                    FindVariableMember(type, field_access);
                }
            }
            //
            // ...If the name to the left of the '.' is reclassified as a TypeName, then this AmbiguousName is
            // reclassified as an ExpressionName
            //
            else if (type = symbol -> TypeCast())
            {
                if (type -> Bad())
                {
                    //
                    // If no error has been detected so far, report this as an error so that
                    // we don't try to generate code later. On the other hand, if an error
                    // had been detected prior to this, don't flood the user with spurious
                    // messages.
                    //
                    if (NumErrors() == 0)
                        ReportAccessedFieldNotFound(field_access, type);
                    field_access -> symbol = control.no_type;
                }
                else if (type == control.null_type || type -> Primitive())
                {
                    ReportSemError(SemanticError::TYPE_NOT_REFERENCE,
                                   base -> LeftToken(),
                                   base -> RightToken(),
                                   type -> Name());
                    field_access -> symbol = control.no_type;
                }
                else
                {
                    TypeAccessCheck(base, type);

                    VariableSymbol *variable_symbol = FindVariableInType(type, field_access);

                    if (variable_symbol)
                    {
                        if (base -> IsName()) // a type name (as opposed to an expression) ? 
                        {
                            if (variable_symbol -> ACC_STATIC())
                            {
                                //
                                // A variable_symbol that is STATIC and FINAL must have an initial value.
                                // If it is dereferenced by a type name, then associate the value with the
                                // subexpression to identify it as a constant subexpression.
                                //
                                if (variable_symbol -> ACC_FINAL())
                                {
                                    //
                                    // If the field declaration of the type has been completely processed,
                                    // simply retrieve the value. Otherwise, compute the value of the
                                    // initialization expression in question on the fly if the variable
                                    // in question is not in the same type. Recall that static variables 
                                    // must be processed in the textual order in which they appear in the
                                    // body of a type. Therefore, if the static initialization of a field
                                    // refers to another variable in the same type it must have appeared
                                    // before the current field declaration otherwise we will emit an error
                                    // message later...
                                    //
                                    if (variable_symbol -> IsDeclarationComplete())
                                        field_access -> value = variable_symbol -> initial_value;
                                    else if (variable_symbol -> declarator)
                                    {
                                        AstVariableDeclarator *declarator = variable_symbol -> declarator -> VariableDeclaratorCast();
                                        //
                                        // If the variable declarator in question exists and its computation is not
                                        // pending (to avoid looping) and it has a simple expression initializer.
                                        //
                                        if (declarator &&
                                            (! declarator -> pending) && 
                                            declarator -> variable_initializer_opt &&
                                            (! declarator -> variable_initializer_opt -> ArrayInitializerCast()))
                                        {
                                            TypeSymbol *type = (TypeSymbol *) variable_symbol -> owner;
                                            Semantic *sem = type -> semantic_environment -> sem;
                                            field_access -> value = sem -> ComputeFinalValue(declarator);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                ReportSemError(SemanticError::NAME_NOT_CLASS_VARIABLE,
                                               field_access -> identifier_token,
                                               field_access -> identifier_token,
                                               identifier_name);
                            }
                        }

                        TypeSymbol *containing_type = (TypeSymbol *) variable_symbol -> owner;
                        if (variable_symbol -> ACC_PRIVATE() &&
                            this_type != containing_type && this_type -> outermost_type == containing_type -> outermost_type)
                        {
                            if (field_access -> IsConstant())
                                field_access -> symbol = variable_symbol;
                            else
                            {
                                AstFieldAccess *method_access = compilation_unit -> ast_pool -> GenFieldAccess();
                                method_access -> base = field_access -> base;  // TODO: WARNING: sharing of Ast subtree !!!
                                method_access -> dot_token = field_access -> identifier_token;
                                method_access -> identifier_token = field_access -> identifier_token;
                                method_access -> symbol = variable_symbol; // the variable in question

                                AstMethodInvocation *p      = compilation_unit -> ast_pool -> GenMethodInvocation();
                                p -> method                  = method_access;
                                p -> left_parenthesis_token  = field_access -> identifier_token;
                                p -> right_parenthesis_token = field_access -> identifier_token;
                                p -> symbol                  = TypeSymbol::GetReadAccessMethod(variable_symbol);

                                field_access -> resolution_opt = p;
                                field_access -> symbol = p -> symbol;
                            }
                        }
                        else
                        {
                            field_access -> symbol = variable_symbol;
                            MemberAccessCheck(field_access, type, containing_type, variable_symbol);
                        }
                    }
                    else 
                    {
                        TypeSymbol *inner_type = FindNestedType(type, field_access -> identifier_token);
                        if (inner_type)
                        {
                            field_access -> symbol = inner_type;
                            TypeAccessCheck(field_access, inner_type);
                        }
                        else
                        {
                            ReportAccessedFieldNotFound(field_access, type);
                            field_access -> symbol = control.no_type;
                        }
                    }
                }
            }
            //
            // ...If the name to the left of the '.' is reclassified as an ExpressionName, then this
            // AmbiguousName is reclassified as an ExpressionName
            //
            else if (type = (TypeSymbol *)
                            (symbol -> VariableCast()
                                     ? symbol -> VariableCast() -> Type((Semantic *) this, field_access -> dot_token)
                                     : (symbol -> MethodCast()
                                                ? symbol -> MethodCast() -> Type((Semantic *) this, field_access -> dot_token)
                                                : NULL)))
            {
                FindVariableMember(type, field_access);
            }
            else // illegal Name !!!
            {
                ReportSemError(SemanticError::UNKNOWN_QUALIFIED_NAME_BASE,
                               base -> LeftToken(),
                               base -> RightToken(),
                               symbol -> Name());
                field_access -> symbol = control.no_type;
            }
        }

        if (type)
        {
            TypeSymbol *parent_type = (type -> IsArray() ? type -> base_type : type);
            if (! parent_type -> Primitive())
                AddDependence(this_type, parent_type, field_access -> identifier_token);
        }
    }

    return;
}


void Semantic::ProcessFieldAccess(Ast *expr)
{
    AstFieldAccess *field_access = (AstFieldAccess *) expr;

    ProcessAmbiguousName(field_access);

    if (field_access -> symbol != control.no_type)
    {
        PackageSymbol *package;
        TypeSymbol *type;

        if (package = field_access -> symbol -> PackageCast())
        {
            ReportSemError(SemanticError::UNKNOWN_AMBIGUOUS_NAME,
                           field_access -> LeftToken(),
                           field_access -> RightToken(),
                           package -> PackageName());
            field_access -> symbol = control.no_type;
        }
        else if ((type = field_access -> symbol -> TypeCast()) && (! field_access -> IsThisAccess()))
        {
            ReportSemError(SemanticError::TYPE_NOT_FIELD,
                           field_access -> LeftToken(),
                           field_access -> RightToken(),
                           type -> Name());
            field_access -> symbol = control.no_type;
        }
        else
        {
            VariableSymbol *variable = field_access -> symbol -> VariableCast();
            if (variable && (! variable -> IsTyped()))
                variable -> ProcessVariableSignature((Semantic *) this, field_access -> identifier_token);
        }
    }

    return;
}


void Semantic::ProcessCharacterLiteral(Ast *expr)
{
    AstCharacterLiteral *char_literal = (AstCharacterLiteral *) expr;

    LiteralSymbol *literal = (LiteralSymbol *) lex_stream -> NameSymbol(char_literal -> character_literal_token);

    if (! literal -> value)
        control.int_pool.FindOrInsertChar(literal);
    if (literal -> value == &control.bad_value)
    {
        ReportSemError(SemanticError::INVALID_CHARACTER_VALUE,
                       char_literal -> LeftToken(),
                       char_literal -> RightToken());
        char_literal -> symbol = control.no_type;
    }
    else
    {
        char_literal -> value = literal -> value;
        char_literal -> symbol = control.char_type;
    }
}


void Semantic::ProcessIntegerLiteral(Ast *expr)
{
    AstIntegerLiteral *int_literal = (AstIntegerLiteral *) expr;

    LiteralSymbol *literal = (LiteralSymbol *) lex_stream -> NameSymbol(int_literal -> integer_literal_token);

    if (! literal -> value)
        control.int_pool.FindOrInsertInt(literal);
    if (literal -> value == &control.bad_value)
    {
        ReportSemError(SemanticError::INVALID_INT_VALUE,
                       int_literal -> LeftToken(),
                       int_literal -> RightToken());
        int_literal -> symbol = control.no_type;
    }
    else
    {
        int_literal -> value = literal -> value;
        int_literal -> symbol = control.int_type;
    }
}


void Semantic::ProcessLongLiteral(Ast *expr)
{
    AstLongLiteral *long_literal = (AstLongLiteral *) expr;

    LiteralSymbol *literal = (LiteralSymbol *) lex_stream -> NameSymbol(long_literal -> long_literal_token);

    if (! literal -> value)
        control.long_pool.FindOrInsertLong(literal);
    if (literal -> value == &control.bad_value)
    {
        ReportSemError(SemanticError::INVALID_LONG_VALUE,
                       long_literal -> LeftToken(),
                       long_literal -> RightToken());
        long_literal -> symbol = control.no_type;
    }
    else
    {
        long_literal -> value = literal -> value;
        long_literal -> symbol = control.long_type;
    }
}


void Semantic::ProcessFloatingPointLiteral(Ast *expr)
{
    AstFloatingPointLiteral *float_literal = (AstFloatingPointLiteral *) expr;

    LiteralSymbol *literal = (LiteralSymbol *) lex_stream -> NameSymbol(float_literal -> floating_point_literal_token);

    if (! literal -> value)
        control.float_pool.FindOrInsertFloat(literal);
    if (literal -> value == &control.bad_value)
    {
        ReportSemError(SemanticError::INVALID_FLOAT_VALUE,
                       float_literal -> LeftToken(),
                       float_literal -> RightToken());
        float_literal -> symbol = control.no_type;
    }
    else
    {
        float_literal -> value = literal -> value;
        float_literal -> symbol = control.float_type;
    }
}


void Semantic::ProcessDoubleLiteral(Ast *expr)
{
    AstDoubleLiteral *double_literal = (AstDoubleLiteral *) expr;

    LiteralSymbol *literal = (LiteralSymbol *) lex_stream -> NameSymbol(double_literal -> double_literal_token);

    if (! literal -> value)
        control.double_pool.FindOrInsertDouble(literal);
    if (literal -> value == &control.bad_value)
    {
        ReportSemError(SemanticError::INVALID_DOUBLE_VALUE,
                       double_literal -> LeftToken(),
                       double_literal -> RightToken());
        double_literal -> symbol = control.no_type;
    }
    else
    {
        double_literal -> value = literal -> value;
        double_literal -> symbol = control.double_type;
    }
}


void Semantic::ProcessTrueLiteral(Ast *expr)
{
    AstExpression *true_literal = (AstTrueLiteral *) expr;

    true_literal -> value = control.int_pool.FindOrInsert((int) 1);
    true_literal -> symbol = control.boolean_type;
}


void Semantic::ProcessFalseLiteral(Ast *expr)
{
    AstExpression *false_literal = (AstFalseLiteral *) expr;

    false_literal -> value = control.int_pool.FindOrInsert((int) 0);
    false_literal -> symbol = control.boolean_type;
}


void Semantic::ProcessStringLiteral(Ast *expr)
{
    AstStringLiteral *string_literal = (AstStringLiteral *) expr;

    LiteralSymbol *literal = (LiteralSymbol *) lex_stream -> NameSymbol(string_literal -> string_literal_token);

    if (! literal -> value)
        control.Utf8_pool.FindOrInsertString(literal);
    if (literal -> value == &control.bad_value)
    {
        ReportSemError(SemanticError::INVALID_STRING_VALUE,
                       string_literal -> LeftToken(),
                       string_literal -> RightToken());
        string_literal -> symbol = control.no_type;
    }
    else
    {
        string_literal -> value = literal -> value;
        string_literal -> symbol = control.String();
    }
}


void Semantic::ProcessArrayAccess(Ast *expr)
{
    AstArrayAccess *array_access = (AstArrayAccess *) expr;

    //
    // This operation may throw NullPointerException or IndefOutOfBoundsException
    //
    SymbolSet *exception_set = TryExceptionTableStack().Top();
    if (exception_set)
    {
        exception_set -> AddElement(control.RuntimeException());
        exception_set -> AddElement(control.Error());
    }

    ProcessExpression(array_access -> base);
    ProcessExpression(array_access -> expression);
    array_access -> expression = PromoteUnaryNumericExpression(array_access -> expression);
    if (array_access -> expression -> Type() != control.int_type && array_access -> expression -> symbol != control.no_type)
    {
        ReportSemError(SemanticError::TYPE_NOT_INTEGER,
                       array_access -> expression -> LeftToken(),
                       array_access -> expression -> RightToken(),
                       array_access -> expression -> Type() -> Name());
    }

    TypeSymbol *array_type = array_access -> base -> Type();
    if (array_type -> IsArray())
        array_access -> symbol = array_type -> ArraySubtype();
    else
    {
        if (array_type != control.no_type)
            ReportSemError(SemanticError::TYPE_NOT_ARRAY,
                           array_access -> base -> LeftToken(),
                           array_access -> base -> RightToken(),
                           array_access -> base -> Type() -> Name());
        array_access -> symbol = control.no_type;
    }

    return;
}


MethodSymbol *Semantic::FindMethodMember(TypeSymbol *type, AstMethodInvocation *method_call)
{
    MethodSymbol *method = NULL;
    AstFieldAccess *field_access = method_call -> method -> FieldAccessCast();

    if (type -> Bad())
    {
        //
        // If no error has been detected so far, report this as an error so that
        // we don't try to generate code later. On the other hand, if an error
        // had been detected prior to this, don't flood the user with spurious
        // messages.
        //
        if (NumErrors() == 0)
            ReportMethodNotFound(method_call, lex_stream -> Name(field_access -> identifier_token));
        method_call -> symbol = control.no_type;
    }
    else if (type == control.null_type || type -> Primitive())
    {
        ReportSemError(SemanticError::TYPE_NOT_REFERENCE,
                       field_access -> base -> LeftToken(),
                       field_access -> base -> RightToken(),
                       type -> Name());
        method_call -> symbol = control.no_type;
    }
    else
    {
        TypeSymbol *this_type = ThisType();
        TypeAccessCheck(field_access -> base, type);

        method = FindMethodInType(type, method_call);

        if (method)
        {
            if (method -> ACC_PRIVATE() && this_type != method -> containing_type
                                        && this_type -> outermost_type == method -> containing_type -> outermost_type)
                method_call -> symbol = TypeSymbol::GetReadAccessMethod(method);
            else
            {
                method_call -> symbol = method;
                MemberAccessCheck(field_access, type, method -> containing_type, method);
            }
        }
        else method_call -> symbol = control.no_type;
    }

    return method;
}


void Semantic::ProcessMethodName(AstMethodInvocation *method_call)
{
    TypeSymbol *this_type = ThisType();

    //
    // This operation may throw:
    //
    //        OutOfMemoryError
    //        NoSuchMethodError
    //        IllegalAccessError
    //        IncompatibleClassChangeError
    //
    SymbolSet *exception_set = TryExceptionTableStack().Top();
    if (exception_set)
    {
        exception_set -> AddElement(control.RuntimeException());
        exception_set -> AddElement(control.Error());
    }

    AstSimpleName *simple_name;

    if (simple_name = method_call -> method -> SimpleNameCast())
    {
        SemanticEnvironment *where_found;
        MethodSymbol *method = FindMethodInEnvironment(where_found, state_stack.Top(), method_call);

        if (! method)
            method_call -> symbol = control.no_type;
        else
        {
            if (! method -> ACC_STATIC())
            {
                //
                // We are in a static region if we are:
                //     . in the body of a static method
                //     . in the body of a static initializer
                //     . precessing an initializer expression for a static variable.
                //
                // See StaticRegion() Semantic.h for more detail.
                //
                // Note that a constructor is never static.
                //
                if (StaticRegion())
                {
                    ReportSemError(SemanticError::METHOD_NOT_CLASS_METHOD,
                                   simple_name -> identifier_token,
                                   method_call -> right_parenthesis_token,
                                   lex_stream -> Name(simple_name -> identifier_token));
                }
                else if (ExplicitConstructorInvocation())
                {
                    if (this_type -> IsSubclass(method -> containing_type))
                    {
                        //
                        // If the method in question is an instance method
                        // that is declared in this_type (this_type is definitely
                        // a class) or one of its super classes, then we have an error -> 
                        //
                        ReportSemError(SemanticError::INSTANCE_METHOD_IN_EXPLICIT_CONSTRUCTOR_INVOCATION,
                                       method_call -> LeftToken(),
                                       method_call -> RightToken(),
                                       method -> Header(),
                                       method -> containing_type -> Name());
                    }
                }
            }

            method_call -> symbol = method;

            //
            // If the method is a private method belonging to an outer type,
            // give the ast simple_name access to its read_method.
            //
            if (where_found != state_stack.Top())
                CreateAccessToScopedMethod(method_call, where_found -> Type());
        }
    }
    else
    {
        AstFieldAccess *field_access = method_call -> method -> FieldAccessCast();
        AstExpression* base = field_access -> base;
        AstFieldAccess *sub_field_access = base -> FieldAccessCast();

        if (base -> SimpleNameCast() || sub_field_access)
             ProcessAmbiguousName(base);
        else ProcessExpression(base);

        if (base -> symbol == control.no_type)
        {
            method_call -> symbol = control.no_type;
            return;
        }

        TypeSymbol *type = NULL;
        Symbol *symbol = base -> symbol;

        //
        // If the base is a "super" field access, resolve it before proceeding 
        //
        if (sub_field_access && sub_field_access -> IsSuperAccess())
        {
            if (sub_field_access -> Type() == control.no_type)
                method_call -> symbol = control.no_type;
            else if (sub_field_access -> Type() == control.Object())
            {
                ReportSemError(SemanticError::OBJECT_HAS_NO_SUPER_TYPE,
                               sub_field_access -> LeftToken(),
                               sub_field_access -> RightToken(),
                               sub_field_access -> Type() -> ContainingPackage() -> PackageName(),
                               sub_field_access -> Type() -> ExternalName());
                method_call -> symbol = control.no_type;
            }
            else
            {
                MethodSymbol *method = FindMethodMember(sub_field_access -> Type() -> super, method_call);

                //
                // TODO: This test was added in order to pass the test in section 8.4.3.1, page 159.
                //       All I can find in the spec is that one example. Nowhere else could I find a
                //       more formal statement.
                //
                if (method && method -> ACC_ABSTRACT())
                {
                    ReportSemError(SemanticError::ABSTRACT_METHOD_INVOCATION,
                                   field_access -> LeftToken(),
                                   field_access -> identifier_token,
                                   lex_stream -> Name(field_access -> identifier_token));
                }
            }
        }
        else if (type = symbol -> TypeCast())
        {
            if (type -> Bad())
            {
                //
                // If no error has been detected so far, report this as an error so that
                // we don't try to generate code later. On the other hand, if an error
                // had been detected prior to this, don't flood the user with spurious
                // messages.
                //
                if (NumErrors() == 0)
                    ReportMethodNotFound(method_call, lex_stream -> Name(field_access -> identifier_token));
                method_call -> symbol = control.no_type;
            }
            else if (type == control.null_type || type -> Primitive())
            {
                ReportSemError(SemanticError::TYPE_NOT_REFERENCE,
                               base -> LeftToken(),
                               base -> RightToken(),
                               type -> Name());
                method_call -> symbol = control.no_type;
            }
            else
            {
                TypeAccessCheck(base, type);

                MethodSymbol *method = FindMethodInType(type, method_call);

                if (method)
                {
                    if (base -> IsName() && (! method -> ACC_STATIC()))
                    {
                        ReportSemError(SemanticError::METHOD_NOT_CLASS_METHOD,
                                       field_access -> LeftToken(),
                                       field_access -> identifier_token,
                                       lex_stream -> Name(field_access -> identifier_token));
                    }
                    //
                    // TODO: This test was added in order to pass the test in section 8.4.3.1, page 159.
                    //       All I can find in the spec is that one example. Nowhere else could I find a
                    //       more formal statement.
                    //
                    else if (base -> SuperExpressionCast() && method -> ACC_ABSTRACT())
                        ReportSemError(SemanticError::ABSTRACT_METHOD_INVOCATION,
                                       field_access -> LeftToken(),
                                       field_access -> identifier_token,
                                       lex_stream -> Name(field_access -> identifier_token));

                    if (method -> ACC_PRIVATE() && this_type != method -> containing_type
                                                && this_type -> outermost_type == method -> containing_type -> outermost_type)
                        method_call -> symbol = TypeSymbol::GetReadAccessMethod(method);
                    else
                    {
                        method_call -> symbol = method;
                        MemberAccessCheck(field_access, type, method -> containing_type, method);
                    }
                }
                else method_call -> symbol = control.no_type;
            }
        }
        else if (type = (TypeSymbol *)
                        (symbol -> VariableCast()
                                 ? symbol -> VariableCast() -> Type((Semantic *) this, field_access -> dot_token)
                                 : (symbol -> MethodCast()
                                            ? symbol -> MethodCast() -> Type((Semantic *) this, field_access -> dot_token)
                                            : NULL)))
        {
            (void) FindMethodMember(type, method_call);
        }
        else // illegal Name !!!
        {
            PackageSymbol *package = symbol -> PackageCast();
            NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token);

            if (package && (package -> FindTypeSymbol(name_symbol) ||
                            Control::GetFile(package, name_symbol, control.option.depend)))
            {
                ReportSemError(SemanticError::TYPE_NOT_METHOD,
                               method_call -> LeftToken(),
                               method_call -> RightToken(),
                               name_symbol -> Name());
            }
            else
            {
                ReportSemError(SemanticError::UNKNOWN_QUALIFIED_NAME_BASE,
                               field_access -> base -> LeftToken(),
                               field_access -> base -> RightToken(),
                               symbol -> Name());
            }
            method_call -> symbol = control.no_type;
        }

        if (type)
        {
            TypeSymbol *parent_type = (type -> IsArray() ? type -> base_type : type);
            if (! parent_type -> Primitive())
                AddDependence(this_type, parent_type, field_access -> identifier_token);
        }
    }

    if (method_call -> symbol != control.no_type)
    {
        MethodSymbol *method = (MethodSymbol *) method_call -> symbol;

        if (exception_set)
        {
            for (int i = method -> NumThrows((Semantic *) this, method_call -> method -> RightToken()) - 1; i >= 0; i--)
                exception_set -> AddElement(method -> Throws(i));
// TODO: what to do?
//            if (! method -> ACC_STATIC())
//                exception_set -> AddElement(NullPointerException());
//            if (method -> ACC_NATIVE())
//                exception_set -> AddElement(control.UnsatisfiedLinkError());
        }

        for (int i = 0; i < method_call -> NumArguments(); i++)
        {
            AstExpression *expr = method_call -> Argument(i);
            if (expr -> Type() != method -> FormalParameter(i) -> Type())
                method_call -> Argument(i) = ConvertToType(expr, method -> FormalParameter(i) -> Type());
        }

        //
        // Recall that an instance initializer in the body of an anonymous type can
        // throw any exception. The test below allows us to skip such blocks.
        //
        if (! (this_type -> Anonymous() && ThisMethod() && ThisMethod() -> Identity() == control.block_init_name_symbol))
        {
            for (int k = method -> NumThrows((Semantic *) this, method_call -> method -> RightToken()) - 1; k >= 0; k--)
            {
                TypeSymbol *exception = method -> Throws(k);
                if (! CatchableException(exception))
                {
                    ReportSemError(SemanticError::UNCATCHABLE_METHOD_THROWN_CHECKED_EXCEPTION,
                                   method_call -> LeftToken(),
                                   method_call -> RightToken(),
                                   method -> Header(),
                                   exception -> ContainingPackage() -> PackageName(),
                                   exception -> ExternalName());
                }
            }
        }
    }

    return;
}


void Semantic::ProcessMethodInvocation(Ast *expr)
{
    AstMethodInvocation *method_call = (AstMethodInvocation *) expr;

    bool no_bad_argument = true;

    for (int i = 0; i < method_call -> NumArguments(); i++)
    {
        AstExpression *expr = method_call -> Argument(i);
        ProcessExpression(expr); // TODO: ProcessExpressionOrStringConstant(expr);
        no_bad_argument = no_bad_argument && (expr -> symbol != control.no_type);
    }

    if (no_bad_argument)
    {
        ProcessMethodName(method_call);
        if (method_call -> symbol != control.no_type)
        {
            MethodSymbol *method = (MethodSymbol *) method_call -> symbol;
            if (! method -> IsTyped())
                method -> ProcessMethodSignature((Semantic *) this, method_call -> left_parenthesis_token);
        }
    }
    else method_call -> symbol = control.no_type;

    return;
}


void Semantic::ProcessNullLiteral(Ast *expr)
{
    AstNullLiteral *null_literal = (AstNullLiteral *) expr;
    null_literal -> value = control.NullValue();
    null_literal -> symbol = control.null_type;

    return;
}


void Semantic::ProcessThisExpression(Ast *expr)
{
    AstThisExpression *this_expression = (AstThisExpression *) expr;

    if (StaticRegion())
    {
        ReportSemError(SemanticError::MISPLACED_THIS_EXPRESSION,
                       this_expression -> LeftToken(),
                       this_expression -> RightToken());
        this_expression -> symbol = control.no_type;
    }
    else if (ExplicitConstructorInvocation())
    {
        ReportSemError(SemanticError::THIS_IN_EXPLICIT_CONSTRUCTOR_INVOCATION,
                       this_expression -> LeftToken(),
                       this_expression -> RightToken(),
                       lex_stream -> Name(this_expression -> this_token));
        this_expression -> symbol = control.no_type;
    }
    else this_expression -> symbol = ThisType();

    return;
}


void Semantic::ProcessSuperExpression(Ast *expr)
{
    AstSuperExpression *super_expression = (AstSuperExpression *) expr;

    if (StaticRegion() || ThisType() == control.Object())
    {
         ReportSemError(SemanticError::MISPLACED_SUPER_EXPRESSION,
                        super_expression -> LeftToken(),
                        super_expression -> RightToken());
         super_expression -> symbol = control.no_type;
    }
    else if (ExplicitConstructorInvocation())
    {
        ReportSemError(SemanticError::THIS_IN_EXPLICIT_CONSTRUCTOR_INVOCATION,
                       super_expression -> LeftToken(),
                       super_expression -> RightToken(),
                       lex_stream -> Name(super_expression -> super_token));
         super_expression -> symbol = control.no_type;
    }
    else super_expression -> symbol = ThisType() -> super;
}


void Semantic::ProcessParenthesizedExpression(Ast *expr)
{
    AstParenthesizedExpression *parenthesized = (AstParenthesizedExpression *) expr;

    ProcessExpression(parenthesized -> expression);
    parenthesized -> value = parenthesized -> expression -> value;
    parenthesized -> symbol = parenthesized -> expression -> symbol;
}              


void Semantic::UpdateGeneratedLocalConstructor(MethodSymbol *constructor)
{
    TypeSymbol *local_type = constructor -> containing_type;
    MethodSymbol *local_constructor = constructor -> LocalConstructor();
assert(local_constructor -> IsGeneratedLocalConstructor());
    BlockSymbol *block_symbol = local_constructor -> block_symbol;

    for (int i = 0; i < constructor -> NumFormalParameters(); i++)
    {
        VariableSymbol *param = constructor -> FormalParameter(i),
                       *symbol = block_symbol -> FindVariableSymbol(param -> Identity());
assert(symbol);
        symbol -> SetExternalIdentity(param -> ExternalIdentity()); // TODO: do we really need this ?
        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);
    }

    //
    // If we are dealing with a constructor generated for an anonymous type and
    // the super type of the anonymous type is an inner type then the generated
    // constructor accepts an additional formal parameter which is the containing
    // type of the super type, and the name of the parameter is #0.
    //
    VariableSymbol *super_this0_variable = block_symbol -> FindVariableSymbol(control.MakeParameter(0));
    if (super_this0_variable)
    {
        super_this0_variable -> SetLocalVariableIndex(block_symbol -> max_variable_index++);
        local_constructor -> AddFormalParameter(super_this0_variable);
    }
    local_constructor -> SetSignature(control);

    //
    //
    //
    AstConstructorDeclaration *constructor_declaration = (AstConstructorDeclaration *)
                                                          constructor -> method_or_constructor_declaration;
assert(constructor_declaration -> ConstructorDeclarationCast());
    AstConstructorBlock *constructor_block = constructor_declaration -> constructor_body;

    if (! (constructor_block -> explicit_constructor_invocation_opt &&
           constructor_block -> explicit_constructor_invocation_opt -> ThisCallCast()))
    {
        constructor_block -> AllocateLocalInitStatements(local_type -> NumConstructorParameters());

        //
        // Generate an assignment statement for each local variable parameter.
        // Note that we do not initialize the this$0 here as the real constructor
        // will do that. If the local_type is static, its constructor_parameters
        // list does not start with this$0.
        //
        for (int i = (local_type -> ACC_STATIC() ? 0 : 1); i < local_type -> NumConstructorParameters(); i++)
        {
            VariableSymbol *param = local_type -> ConstructorParameter(i),
                           *symbol = block_symbol -> FindVariableSymbol(param -> Identity());
assert(symbol);
            AstSimpleName *lhs = compilation_unit -> ast_pool -> GenSimpleName(constructor_block -> left_brace_token);
            lhs -> symbol = param;

            AstSimpleName *rhs = compilation_unit -> ast_pool -> GenSimpleName(constructor_block -> left_brace_token);
            rhs -> symbol = symbol;

            AstAssignmentExpression *assign = compilation_unit -> ast_pool
                                                                -> GenAssignmentExpression(AstAssignmentExpression::EQUAL,
                                                                                            constructor_block -> left_brace_token);
            assign -> left_hand_side = lhs;
            assign -> expression     = rhs;
            assign -> symbol         = lhs -> Type();

            AstExpressionStatement *stmt = compilation_unit -> ast_pool -> GenExpressionStatement();
            stmt -> expression          = assign;
            stmt -> semicolon_token_opt = constructor_block -> left_brace_token;

            stmt -> is_reachable = true;
            stmt -> can_complete_normally = true;

            constructor_block -> AddLocalInitStatement(stmt);
        }
    }

    //
    //
    //
    AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(constructor_block -> left_brace_token);
    simple_name -> symbol = constructor;
assert(! constructor -> IsGeneratedLocalConstructor());

    AstMethodInvocation *method_call = compilation_unit -> ast_pool -> GenMethodInvocation();
    method_call -> method                  = simple_name;
    method_call -> left_parenthesis_token  = constructor_block -> left_brace_token;
    method_call -> right_parenthesis_token = constructor_block -> left_brace_token;
    method_call -> symbol                  = simple_name -> symbol;

    method_call -> AllocateArguments(constructor -> NumFormalParameters() + 1);
    if (! local_type -> ACC_STATIC())
    {
        AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(constructor_block -> left_brace_token);
        simple_name -> symbol = block_symbol -> FindVariableSymbol(control.this0_name_symbol);
assert(simple_name -> symbol);
        method_call -> AddArgument(simple_name);
    }

    for (int k = 0; k < constructor -> NumFormalParameters(); k++)
    {
        VariableSymbol *param = constructor -> FormalParameter(k),
                       *symbol = block_symbol -> FindVariableSymbol(param -> Identity());
        AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(constructor_block -> left_brace_token);
        simple_name -> symbol = symbol;
        method_call -> AddArgument(simple_name);
    }

    AstExpressionStatement *stmt = compilation_unit -> ast_pool -> GenExpressionStatement();
    stmt -> expression          = method_call;
    stmt -> semicolon_token_opt = constructor_block -> left_brace_token;

    stmt -> is_reachable = true;
    stmt -> can_complete_normally = true;

    constructor_block -> original_constructor_invocation = stmt;

    return;
}


void Semantic::UpdateLocalConstructors(TypeSymbol *inner_type)
{
    if (! ThisType() -> IsLocal()) // the method containing inner_type is not itself embedded in another method
    {
        //
        // Compute the set of local_classes we need to process here - they are
        // the inner_type itself and all the classes that are embedded in its body.
        //
        Tuple<TypeSymbol *> local_classes(8);

        TypeSymbol *outermost_type = inner_type -> outermost_type;
        if (outermost_type -> local) // The set of local types in the outermost type is not empty?
        {
            for (TypeSymbol *local_type = (TypeSymbol *) outermost_type -> local -> FirstElement();
                             local_type;
                             local_type = (TypeSymbol *) outermost_type -> local -> NextElement())
            {
                if (local_type -> CanAccess(inner_type))
                    local_classes.Next() = local_type;
            }
        }

        for (int j = 0; j < outermost_type -> num_anonymous_types(); j++)
        {
            if (outermost_type -> AnonymousType(j) -> CanAccess(inner_type))
                local_classes.Next() = outermost_type -> AnonymousType(j);
        }

        //
        // We now update each type T2 containing a call to a constructor of
        // T1 to make sure that T2 has a copy of or access to all the local
        // variables required by T1.
        //
        for (int k = 0; k < local_classes.Length(); k++)
        {
            TypeSymbol *target_local_type = local_classes[k];

            for (int i = 0; i < target_local_type -> NumLocalConstructorCallEnvironments(); i++)
            {
                SemanticEnvironment *env = target_local_type -> LocalConstructorCallEnvironment(i);
                TypeSymbol *source_local_type = env -> Type();
                if (! source_local_type -> CanAccess(target_local_type))
                {
                    for (int j = (target_local_type -> ACC_STATIC() ? 0 : 1);
                         j < target_local_type -> NumConstructorParameters(); j++)
                    {
                        VariableSymbol *local = target_local_type -> ConstructorParameter(j) -> accessed_local;
                        if (env -> symbol_table.FindVariableSymbol(local -> Identity()) != local)
                            source_local_type -> FindOrInsertLocalShadow(local);
                    }
                }
            }
        }

        //
        // Now update the constructor bodies to reflect the new local variable counts and mark the local_type completed.
        //
        for (int l = 0; l < local_classes.Length(); l++)
        {
            TypeSymbol *local_type = local_classes[l];

            AstClassDeclaration *class_declaration = local_type -> declaration -> ClassDeclarationCast();
            AstClassInstanceCreationExpression *class_creation = local_type -> declaration -> ClassInstanceCreationExpressionCast();
assert(class_declaration || class_creation);
            AstClassBody *class_body = (class_declaration ? class_declaration -> class_body : class_creation -> class_body_opt);

            if (class_body -> default_constructor)
                 UpdateGeneratedLocalConstructor(class_body -> default_constructor -> constructor_symbol);
            else
            {
                for (int i = 0; i < class_body -> NumConstructors(); i++)
                    UpdateGeneratedLocalConstructor(class_body -> Constructor(i) -> constructor_symbol);

                for (int k = 0; k < local_type -> NumPrivateAccessConstructors(); k++)
                    UpdateGeneratedLocalConstructor(local_type -> PrivateAccessConstructor(k));
            }

            local_type -> MarkLocalClassProcessingCompleted();
        }

        //
        // Now update the constructor calls
        //
        for (int m = 0; m < local_classes.Length(); m++)
        {
            TypeSymbol *target_local_type = local_classes[m];
assert(target_local_type -> LocalClassProcessingCompleted());

            for (int i = 0; i < target_local_type -> NumLocalConstructorCallEnvironments(); i++)
            {
                Ast *call = target_local_type -> LocalConstructorCallEnvironment(i) -> ast_construct;
                SemanticEnvironment *env = target_local_type -> LocalConstructorCallEnvironment(i);
                TypeSymbol *source_local_type = env -> Type();

                AstClassInstanceCreationExpression *class_creation;
                AstSuperCall *super_call;
                AstThisCall *this_call;

                if (class_creation = call -> ClassInstanceCreationExpressionCast())
                {
                    if (class_creation -> symbol != control.no_type)
                    {
                        if (source_local_type -> CanAccess(target_local_type))
                        {
                            for (int j = (target_local_type -> ACC_STATIC() ? 0 : 1);
                                 j < target_local_type -> NumConstructorParameters(); j++)
                            {
                                VariableSymbol *local = target_local_type -> ConstructorParameter(j) -> accessed_local;
                                AstSimpleName *simple_name = compilation_unit -> ast_pool
                                                                               -> GenSimpleName(class_creation -> new_token);
                                simple_name -> symbol = local;
                                if (source_local_type != target_local_type)
                                {
                                    state_stack.Push(source_local_type -> semantic_environment);
                                    CreateAccessToScopedVariable(simple_name, target_local_type);
                                    state_stack.Pop();
                                }
                                class_creation -> AddLocalArgument(simple_name);
                            }
                        }
                        else
                        {
                            for (int j = (target_local_type -> ACC_STATIC() ? 0 : 1);
                                 j < target_local_type -> NumConstructorParameters(); j++)
                            {
                                VariableSymbol *local = target_local_type -> ConstructorParameter(j) -> accessed_local;

                                AstSimpleName *simple_name = compilation_unit -> ast_pool
                                                                               -> GenSimpleName(class_creation -> new_token);
                                simple_name -> symbol = (env -> symbol_table.FindVariableSymbol(local -> Identity()) == local
                                                              ? local
                                                              : source_local_type -> FindOrInsertLocalShadow(local));
assert(simple_name -> symbol -> VariableCast());
                                class_creation -> AddLocalArgument(simple_name);
                            }
                        }

                        MethodSymbol *constructor = (MethodSymbol *) class_creation -> class_type -> symbol;
assert(constructor);
assert(constructor -> MethodCast());
assert(! constructor -> IsGeneratedLocalConstructor());
assert(constructor -> LocalConstructor());
                        class_creation -> class_type -> symbol = constructor -> LocalConstructor();
                    }
                }
                else if (super_call = call -> SuperCallCast())
                {
                    if (super_call -> symbol -> MethodCast())
                    {
                        for (int j = (target_local_type -> ACC_STATIC() ? 0 : 1);
                             j < target_local_type -> NumConstructorParameters(); j++)
                        {
                            VariableSymbol *local = target_local_type -> ConstructorParameter(j) -> accessed_local;

                            AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(super_call -> super_token);
                            simple_name -> symbol = env -> symbol_table.FindVariableSymbol(local -> Identity());
assert(simple_name -> symbol -> VariableCast()); 
                            super_call -> AddLocalArgument(simple_name);
                        }

                        MethodSymbol *constructor = (MethodSymbol *) super_call -> symbol;
assert(constructor -> MethodCast() && (! constructor -> IsGeneratedLocalConstructor()));
assert(constructor -> LocalConstructor());
                        super_call -> symbol = constructor -> LocalConstructor();
                    }
                }
                else
                {
                    this_call = (AstThisCall *) call;
assert(this_call -> ThisCallCast());

                    if (this_call -> symbol -> MethodCast())
                    {
                        for (int j = (target_local_type -> ACC_STATIC() ? 0 : 1);
                             j < target_local_type -> NumConstructorParameters(); j++)
                        {
                            VariableSymbol *local = target_local_type -> ConstructorParameter(j) -> accessed_local;

                            AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(this_call -> this_token);
                            simple_name -> symbol = env -> symbol_table.FindVariableSymbol(local -> Identity());
assert(simple_name -> symbol -> VariableCast()); 
                            this_call -> AddLocalArgument(simple_name);
                        }

                        MethodSymbol *constructor = (MethodSymbol *) this_call -> symbol;
assert(constructor -> MethodCast() && (! constructor -> IsGeneratedLocalConstructor()));
assert(constructor -> LocalConstructor());
                        this_call -> symbol = constructor -> LocalConstructor();
                    }
                }
            }
        }
    }

    return;
}


void Semantic::GetAnonymousConstructor(AstClassInstanceCreationExpression *class_creation, TypeSymbol *anonymous_type)
{
    LexStream::TokenIndex left_loc  = class_creation -> class_type -> LeftToken(),
                          right_loc = class_creation -> right_parenthesis_token;

    TypeSymbol *super_type = anonymous_type -> super;
    MethodSymbol *super_constructor = FindConstructor(super_type, class_creation, left_loc, right_loc);
    if (! super_constructor)
    {
        class_creation -> class_type -> symbol = control.no_type;
        return;
    }

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

    MethodSymbol *constructor = anonymous_type -> InsertConstructorSymbol(control.init_name_symbol);
    constructor -> SetType(control.void_type);
    constructor -> SetContainingType(anonymous_type);
    constructor -> SetBlockSymbol(block_symbol);
    constructor -> SetACC_PUBLIC();

    //
    // Report error is super constructor has throws clause, but add the exceptions to the local throws
    // clause to avoid spurious errors later !!!
    //
    int num_throws = super_constructor -> NumThrows((Semantic *) this, left_loc);
    if (num_throws > 0)
    {
        for (int i = 0; i < num_throws; i++)
        {
            TypeSymbol *exception = super_constructor -> Throws(i);
            ReportSemError(SemanticError::CONSTRUCTOR_DOES_NOT_THROW_SUPER_EXCEPTION,
                          class_creation -> new_token,
                          class_creation -> RightToken(),
                          StringConstant::US_EMPTY,
                          exception -> ContainingPackage() -> PackageName(),
                          exception -> ExternalName(),
                          super_constructor -> containing_type -> ContainingPackage() -> PackageName(),
                          super_constructor -> containing_type -> ExternalName());

            constructor -> AddThrows(exception);
        }
    }

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

    for (int j = 0; j < super_constructor -> NumFormalParameters(); j++)
    {
        VariableSymbol *param = super_constructor -> FormalParameter(j),
                       *symbol = block_symbol -> InsertVariableSymbol(param -> Identity());
        symbol -> SetType(param -> Type());
        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++;
        constructor -> AddFormalParameter(symbol);
    }

    //
    //
    //
    AstSuperCall *super_call             = compilation_unit -> ast_pool -> GenSuperCall();
    super_call -> base_opt                = class_creation -> base_opt; // save initial base_opt
    super_call -> dot_token_opt           = class_creation -> new_token;
    super_call -> super_token             = class_creation -> new_token;
    super_call -> left_parenthesis_token  = class_creation -> new_token;
    super_call -> right_parenthesis_token = class_creation -> new_token;
    super_call -> semicolon_token         = class_creation -> new_token;

    super_call -> is_reachable            = true;
    super_call -> can_complete_normally   = true;
    super_call -> symbol                  = super_constructor;

    //
    // If it is in a static region, the anonymous class does not need a this$0 argument
    //
    class_creation -> base_opt = (anonymous_type -> ACC_STATIC()
                                           ? (AstExpression *) NULL
                                           : CreateAccessToType(class_creation, anonymous_type -> ContainingType()));

    AstClassBody *class_body = class_creation -> class_body_opt;

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

    AstBlock *block = compilation_unit -> ast_pool -> GenBlock();
    block -> block_symbol = constructor -> block_symbol -> InsertBlockSymbol(1); // this symbol table will be empty
    block -> AllocateBlockStatements(1); // this block contains one statement
    block -> left_brace_token  = class_body -> left_brace_token;
    block -> right_brace_token = class_body -> left_brace_token;

    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                    = class_body -> left_brace_token;
    constructor_block -> explicit_constructor_invocation_opt = super_call;
    constructor_block -> block                               = block;
    constructor_block -> right_brace_token                   = class_body -> left_brace_token;

    AstMethodDeclarator *method_declarator      = compilation_unit -> ast_pool -> GenMethodDeclarator();
    method_declarator -> identifier_token        = left_loc;
    method_declarator -> left_parenthesis_token  = class_creation -> left_parenthesis_token;
    method_declarator -> right_parenthesis_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;

    //
    // Note that the constructor for the anonymous type is not added to the class body here
    // beacause we've already completely compiled it and the arguments to its super call
    // do not contain "valid" SimpleName Ast expressions. It is added to the constructor
    // body later in get_anonymous_type...
    //
    // class_body -> default_constructor = constructor_declaration;
    //
    VariableSymbol *super_this0_variable = NULL;

    if (anonymous_type -> IsLocal())
    {
        GenerateLocalConstructor(constructor);

        MethodSymbol *generated_constructor = constructor -> LocalConstructor();
assert(! constructor -> IsGeneratedLocalConstructor());
assert(generated_constructor);
        block_symbol = generated_constructor -> block_symbol; // use the environment of the generated constructor...

        if (super_call -> base_opt)
        {
            //
            // Add the this$0 parameter for the super type. However, only mark it complete and
            // do not yet assign a number to it. This will be done after we know
            // how many extra "local" variable shadows are needed. See UpdateGeneratedLocalConstructor
            //
            super_this0_variable = block_symbol -> InsertVariableSymbol(control.MakeParameter(0));
            super_this0_variable -> MarkSynthetic();
            super_this0_variable -> SetType(super_call -> base_opt -> Type());
            super_this0_variable -> SetOwner(generated_constructor);
            super_this0_variable -> MarkComplete();
        }

        if (super_type -> IsLocal()) // a local type may use enclosed local variables?
        {
            if (super_type -> LocalClassProcessingCompleted())
            {
                //
                // TODO: Should we set the size for the super_call arguments here ???
                //
                for (int i = 1; i < super_type -> NumConstructorParameters(); i++)
                {
                    VariableSymbol *local = super_type -> ConstructorParameter(i) -> accessed_local;

                    AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(super_call -> super_token);

                    anonymous_type -> FindOrInsertLocalShadow(local);
                    simple_name -> symbol = block_symbol -> FindVariableSymbol(local -> Identity());
assert(simple_name -> symbol);
                    super_call -> AddLocalArgument(simple_name);
                }
assert(super_constructor -> LocalConstructor() && (! super_constructor -> IsGeneratedLocalConstructor()));
                super_call -> symbol = super_constructor -> LocalConstructor();
            }
            else // are we currently within the body of the type in question ?
                super_type -> AddLocalConstructorCallEnvironment(GetEnvironment(super_call));
        }
    }
    else if (super_call -> base_opt)
    {
        super_this0_variable = block_symbol -> InsertVariableSymbol(control.MakeParameter(0));
        super_this0_variable -> MarkSynthetic();
        super_this0_variable -> SetType(super_call -> base_opt -> Type());
        super_this0_variable -> SetOwner(constructor);
        super_this0_variable -> SetLocalVariableIndex(block_symbol -> max_variable_index++);

        constructor -> AddFormalParameter(super_this0_variable);
    }

    //
    // Complete the definition of the constructor and update the super call accordingly.
    //
    if (super_this0_variable)
    {
        class_creation -> AddArgument(super_call -> base_opt); // pass the original base expression as argument to anonymous class.

        AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(class_creation -> new_token);
        simple_name -> symbol = super_this0_variable;
        super_call -> base_opt = simple_name; // pass the base expression argument to the super class
    }

    constructor -> SetSignature(control, this0_variable); // we now have all the information to set the signature of the constructor.

    //
    // Are we guaranteed to have all the info available here? Yes,
    // because if the anonymous type is not local to a method, then its super
    // type cannot be local to a method. Therefore, no extra argument (other than
    // the proper this$0 specified in the base) is needed. If on the other hand the
    // anonymous type is local and its supertype is also local, it must have appeared
    // before the anonymous type and therefore its information has already been computed.
    //
    for (int k = 0; k < super_constructor -> NumFormalParameters(); k++)
    {
        VariableSymbol *param = super_constructor -> FormalParameter(k),
                       *symbol = block_symbol -> FindVariableSymbol(param -> Identity());
assert(symbol);
        AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(class_creation -> new_token);
        simple_name -> symbol = symbol;
        super_call -> AddArgument(simple_name);
    }

    class_creation -> class_type -> symbol = constructor;

    return;
}


TypeSymbol *Semantic::GetAnonymousType(AstClassInstanceCreationExpression *class_creation, TypeSymbol *super_type)
{
    TypeSymbol *this_type = ThisType();

    if (super_type -> ACC_FINAL())
    {
         ReportSemError(SemanticError::SUPER_IS_FINAL,
                        class_creation -> class_type -> LeftToken(),
                        class_creation -> class_type -> RightToken(),
                        super_type -> ContainingPackage() -> PackageName(),
                        super_type -> ExternalName());
    }

    AstClassBody *class_body = class_creation -> class_body_opt;
    TypeSymbol *outermost_type = this_type -> outermost_type;

    //
    // Make up a proper name for the anonymous type
    //
    int num = outermost_type -> num_anonymous_types() + 1;
    wchar_t str[11],
            *p = &str[10];
    *p = U_NULL;
    do
    {
        p--;
        *p = U_0 + (num % 10);
        num /= 10;
    } while (num > 0);

    int length = wcslen(p) + outermost_type -> NameLength() + 1; // +1 for $
    wchar_t *anonymous_name = new wchar_t[length + 1];
    wcscpy(anonymous_name, outermost_type -> Name());
    wcscat(anonymous_name, StringConstant::US__DS_);
    wcscat(anonymous_name, p);

    NameSymbol *name_symbol = control.FindOrInsertName(anonymous_name, length);

assert((! ThisMethod()) || LocalSymbolTable().Top());
    TypeSymbol *inner_type = (ThisMethod() ? LocalSymbolTable().Top() -> InsertAnonymousTypeSymbol(name_symbol)
                                           : this_type -> InsertAnonymousTypeSymbol(name_symbol));
    inner_type -> SetACC_PRIVATE();
    inner_type -> MarkAnonymous();
    inner_type -> outermost_type = outermost_type;
    inner_type -> supertypes_closure = new SymbolSet;
    inner_type -> subtypes_closure = new SymbolSet;
    inner_type -> semantic_environment = new SemanticEnvironment((Semantic *) this, inner_type, state_stack.Top());
    inner_type -> declaration = class_creation;
    inner_type -> file_symbol = source_file_symbol;
    inner_type -> SetOwner(ThisMethod() ? (Symbol *) ThisMethod() : (Symbol *) this_type);
    //
    // Add 3 extra elements for padding. May need a default constructor and other support elements.
    //
    inner_type -> SetSymbolTable(class_body -> NumClassBodyDeclarations() + 3);
    inner_type -> SetLocation();
    inner_type -> SetSignature(control);

    //
    // TODO: As an anonymous type cannot be a super class, it makes sense to mark
    // is final. This allows jikes to be consistent with javac in emitting an
    // error message when the anonymous class is checked in an instanceof
    // operation against an interface. However, this fact is not documented
    // in the 1.1 document. Furthermore, the class file that is emitted for an
    // anonymous flag (when processed by javac) does not have the FINAL flag turned on.
    // We also turn this flag off after processing the body of the anonymmous type.
    // See bolow...
    //
    inner_type -> SetACC_FINAL();

    if (StaticRegion())
         inner_type -> SetACC_STATIC();
    else inner_type -> InsertThis(0);

    if (super_type -> ACC_INTERFACE())
    {
         inner_type -> AddInterface(super_type);
         inner_type -> super = control.Object();
    }
    else inner_type -> super = super_type;

    outermost_type -> AddAnonymousType(inner_type);
    delete [] anonymous_name;

    //
    //
    //
    GetAnonymousConstructor(class_creation, inner_type);

    //
    // Now process the body of the anonymous class !!!
    //
    CheckClassMembers(inner_type, class_body);
    ProcessNestedTypeHeaders(inner_type, class_body);
    if (inner_type -> owner -> MethodCast())
         ProcessSuperTypesOfOuterType(inner_type);
    else ProcessNestedSuperTypes(inner_type);

    //
    // If the class body has not yet been parsed, do so now.
    //
    if (class_body -> UnparsedClassBodyCast())
    {
        if (! control.parser -> InitializerParse(lex_stream, class_body))
             compilation_unit -> kind = Ast::BAD_COMPILATION; // mark the fact that syntax errors were detected
        else
        {
            inner_type -> MarkHeaderProcessed();
            ProcessMembers(inner_type -> semantic_environment, class_body);
            CompleteSymbolTable(inner_type -> semantic_environment, class_body -> left_brace_token, class_body);
        }

        if (! control.parser -> BodyParse(lex_stream, class_body))
             compilation_unit -> kind = Ast::BAD_COMPILATION; // mark the fact that syntax errors were detected
        else ProcessExecutableBodies(inner_type -> semantic_environment, class_body);
    }
    else // The relevant bodies have already been parsed
    {
        inner_type -> MarkHeaderProcessed();
        ProcessMembers(inner_type -> semantic_environment, class_body);
        CompleteSymbolTable(inner_type -> semantic_environment, class_body -> left_brace_token, class_body);
        ProcessExecutableBodies(inner_type -> semantic_environment, class_body);
    }

    //
    // Add the default constructor to the body of the anonymous type.
    // If the symbol was resolve to "no_type" then constructor will be NULL
    //
    MethodSymbol *constructor = class_creation -> class_type -> symbol -> MethodCast();
    if (constructor)
    {
        class_body -> default_constructor = (AstConstructorDeclaration *) constructor -> method_or_constructor_declaration;

        if (inner_type -> IsLocal())
        {
            inner_type -> AddLocalConstructorCallEnvironment(GetEnvironment(class_creation));
            UpdateLocalConstructors(inner_type);
        }
    }

    //
    // TODO: See comment above regarding the setting of this flag.
    //
    inner_type -> ResetACC_FINAL();

    return inner_type;
}


void Semantic::ProcessClassInstanceCreationExpression(Ast *expr)
{
    AstClassInstanceCreationExpression *class_creation = (AstClassInstanceCreationExpression *) expr;

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

    //
    // This operation may throw OutOfMemoryError
    //
    SymbolSet *exception_set = TryExceptionTableStack().Top();
    if (exception_set)
    {
        exception_set -> AddElement(control.RuntimeException());
        exception_set -> AddElement(control.Error());
    }

    Ast *actual_type = class_creation -> class_type -> type;
    TypeSymbol *type;
    if (class_creation -> base_opt)
    {
        ProcessExpression(class_creation -> base_opt);

        TypeSymbol *enclosing_type = class_creation -> base_opt -> Type();
        if (enclosing_type == control.no_type)
        {
            class_creation -> symbol = control.no_type;
            return;
        }
        else if (enclosing_type == control.null_type || enclosing_type -> Primitive())
        {
            ReportSemError(SemanticError::TYPE_NOT_REFERENCE,
                           class_creation -> base_opt -> LeftToken(),
                           class_creation -> base_opt -> RightToken(),
                           enclosing_type -> ExternalName());
            class_creation -> symbol = control.no_type;
            return;
        }

        //
        // The grammar guarantees that the actual type is a simple name.
        //
        type = MustFindNestedType(enclosing_type, actual_type);
        if (type -> ACC_STATIC())
        {
            ReportSemError(SemanticError::STATIC_NOT_INNER_CLASS,
                           actual_type -> LeftToken(),
                           actual_type -> RightToken(),
                           type -> ContainingPackage() -> PackageName(),
                           type -> ExternalName());
        }
    }
    else
    {
        type = MustFindType(actual_type);
        if (type -> IsInner())
            class_creation -> base_opt = CreateAccessToType(class_creation, type -> ContainingType());
    }

 
    bool no_bad_argument = true;
    for (int i = 0; i < class_creation -> NumArguments(); i++)
    {
        AstExpression *expr = class_creation -> Argument(i);
        ProcessExpression(expr); // TODO: ProcessExpressionOrStringConstant(expr);
        no_bad_argument = no_bad_argument && (expr -> symbol != control.no_type);
    }

    TypeSymbol *anonymous_type = NULL;

    if (! no_bad_argument)
    {
        class_creation -> class_type -> symbol = control.no_type;
        class_creation -> symbol = type;
    }
    else
    {
        MethodSymbol *method = FindConstructor((type -> ACC_INTERFACE() ? control.Object() : type),
                                                class_creation,
                                                actual_type -> LeftToken(),
                                                class_creation -> right_parenthesis_token);

        if (! method)
        {
            class_creation -> class_type -> symbol = control.no_type;
            class_creation -> symbol = type;
        }
        else
        {
            if (class_creation -> base_opt &&
                (class_creation -> base_opt -> symbol != control.no_type) && 
                (class_creation -> base_opt -> Type() != method -> containing_type -> ContainingType()))
            {
assert(method -> containing_type);
assert(method -> containing_type -> ContainingType());
assert(class_creation -> base_opt -> Type());
assert(CanMethodInvocationConvert(method -> containing_type -> ContainingType(), class_creation -> base_opt -> Type()));
                class_creation -> base_opt = ConvertToType(class_creation -> base_opt, method -> containing_type -> ContainingType());
            }

            for (int i = 0; i < class_creation -> NumArguments(); i++)
            {
                AstExpression *expr = class_creation -> Argument(i);
                if (expr -> Type() != method -> FormalParameter(i) -> Type())
                    class_creation -> Argument(i) = ConvertToType(expr, method -> FormalParameter(i) -> Type());
            }        

            if (class_creation -> class_body_opt)
                anonymous_type = GetAnonymousType(class_creation, type);
            else
            {
                if (type -> ACC_INTERFACE())
                {
                    ReportSemError(SemanticError::NOT_A_CLASS,
                                   actual_type -> LeftToken(),
                                   actual_type -> RightToken(),
                                   type -> ContainingPackage() -> PackageName(),
                                   type -> ExternalName());
                    class_creation -> symbol = control.no_type;
                    return;
                }
                else if (type -> ACC_ABSTRACT())
                {
                    ReportSemError(SemanticError::ABSTRACT_TYPE_CREATION,
                                   actual_type -> LeftToken(),
                                   actual_type -> RightToken(),
                                   type -> ExternalName());
                }

                class_creation -> class_type -> symbol = method;

                if (exception_set)
                {
                    for (int i = method -> NumThrows((Semantic *) this, actual_type -> RightToken()) - 1; i >= 0; i--)
                        exception_set -> AddElement(method -> Throws(i));
                }

                if (! (ThisType() -> Anonymous() && ThisMethod() && ThisMethod() -> Identity() == control.block_init_name_symbol))
                {
                    for (int k = method -> NumThrows((Semantic *) this, actual_type -> RightToken()) - 1; k >= 0; k--)
                    {
                        TypeSymbol *exception = method -> Throws(k);
                        if (! CatchableException(exception))
                        {
                            ReportSemError(SemanticError::UNCATCHABLE_CONSTRUCTOR_THROWN_CHECKED_EXCEPTION,
                                           actual_type -> LeftToken(),
                                           actual_type -> RightToken(),
                                           type -> ExternalName(),
                                           exception -> ContainingPackage() -> PackageName(),
                                           exception -> ExternalName());
                        }
                    }
                }
            }

            class_creation -> symbol = (anonymous_type ? anonymous_type : type);

            if (method -> ACC_PRIVATE() && ThisType() != type && ThisType() -> outermost_type == type -> outermost_type)
            {
                //
                // TODO: Awaiting language clarification.
                //
                ReportSemError(SemanticError::PRIVATE_ENCLOSED_CONSTRUCTOR,
                               class_creation -> new_token,
                               class_creation -> right_parenthesis_token,
                               method -> Header());

                method = TypeSymbol::GetReadAccessMethod(method);
                class_creation -> class_type -> symbol = method;
            }
            else ConstructorAccessCheck(class_creation, method);

            //
            // A local type may use enclosed local variables. So, we at least allocate the 
            // space for adding these extra arguments. If the type being created has already been
            // fully processed, add the extra arguments here.
            //
            if ((! anonymous_type) && type -> IsLocal())
            {
                if (type -> LocalClassProcessingCompleted() && method -> LocalConstructor())
                {
assert(! method -> IsGeneratedLocalConstructor());
                    class_creation -> class_type -> symbol = method -> LocalConstructor();
assert(method -> LocalConstructor() -> signature);

                    //
                    // Are we currently within the body of the method that contains
                    // the local type in question?
                    //
                    if (type -> owner == ThisMethod())
                    {
                        for (int i = (type -> ACC_STATIC() ? 0 : 1); i < type -> NumConstructorParameters(); i++)
                        {
                            VariableSymbol *local = type -> ConstructorParameter(i) -> accessed_local;

                            AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(class_creation -> new_token);
                            simple_name -> symbol = local;
                            class_creation -> AddLocalArgument(simple_name);
                        }
                    }
                    else
                    {
                        for (int i = (type -> ACC_STATIC() ? 0 : 1); i < type -> NumConstructorParameters(); i++)
                        {
                            VariableSymbol *local = type -> ConstructorParameter(i) -> accessed_local;

                            AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(class_creation -> new_token);
                            simple_name -> symbol = ThisType() -> FindOrInsertLocalShadow(local);
                            class_creation -> AddLocalArgument(simple_name);
                        }
                    }
                }
                else // are we within body of type in question? Save processing for later. See ProcessClassDeclaration in body.cpp
                    type -> AddLocalConstructorCallEnvironment(GetEnvironment(class_creation));
            }
        }
    }

    return;
}


void Semantic::ProcessArrayCreationExpression(Ast *expr)
{
    AstArrayCreationExpression *array_creation = (AstArrayCreationExpression *) expr;

    //
    // This operation may throw OutOfMemoryError or NegativeArraySizeException
    //
    SymbolSet *exception_set = TryExceptionTableStack().Top();
    if (exception_set)
    {
        exception_set -> AddElement(control.RuntimeException());
        exception_set -> AddElement(control.Error());
    }

    AstArrayType *array_type;

    TypeSymbol *type;

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

        AstPrimitiveType *primitive_type = array_type -> type -> PrimitiveTypeCast();
        type = (primitive_type ? FindPrimitiveType(primitive_type) : MustFindType(array_type -> type));
    }
    else
    {
        AstPrimitiveType *primitive_type = array_creation -> array_type -> PrimitiveTypeCast();
        type = (primitive_type ? FindPrimitiveType(primitive_type) : MustFindType(array_creation -> array_type));
    }

    int num_dimensions = (array_type ? array_type -> NumBrackets()
                                     : array_creation -> NumDimExprs() + array_creation -> NumBrackets());

    if (num_dimensions > 0)
        type = type -> GetArrayType((Semantic *) this, num_dimensions);
    array_creation -> symbol = type;

    for (int i = 0; i < array_creation -> NumDimExprs(); i++)
    {
        AstDimExpr *dim_expr = array_creation -> DimExpr(i);
        ProcessExpression(dim_expr -> expression);
        AstExpression *expr = PromoteUnaryNumericExpression(dim_expr -> expression);
        if (expr -> Type() != control.int_type && expr -> symbol != control.no_type)
        {
            ReportSemError(SemanticError::TYPE_NOT_INTEGER,
                           dim_expr -> expression -> LeftToken(),
                           dim_expr -> expression -> RightToken(),
                           dim_expr -> expression -> Type() -> Name());
        }
        dim_expr -> expression = expr;
    }

    if (array_creation -> array_initializer_opt)
        ProcessArrayInitializer((AstArrayInitializer *) array_creation -> array_initializer_opt, type);

    return;
}


void Semantic::ProcessPostUnaryExpression(Ast *expr)
{
    AstPostUnaryExpression *postfix_expression = (AstPostUnaryExpression *) expr;

    ProcessExpression(postfix_expression -> expression);
    postfix_expression -> symbol = postfix_expression -> expression -> symbol;

    if (postfix_expression -> symbol != control.no_type)
    {
        if (! postfix_expression -> expression -> IsLeftHandSide())
        {
            ReportSemError(SemanticError::NOT_A_NUMERIC_VARIABLE,
                           postfix_expression -> expression -> LeftToken(),
                           postfix_expression -> expression -> RightToken(),
                           postfix_expression -> expression -> Type() -> Name());
            postfix_expression -> symbol = control.no_type;
        }
        else if (! control.IsNumeric(postfix_expression -> Type()))
        {
            ReportSemError(SemanticError::TYPE_NOT_NUMERIC,
                           postfix_expression -> expression -> LeftToken(),
                           postfix_expression -> expression -> RightToken(),
                           postfix_expression -> Type() -> Name());
            postfix_expression -> symbol = control.no_type;
        }
        else if (! postfix_expression -> expression -> ArrayAccessCast()) // some kind of name
        {
            MethodSymbol *read_method = NULL;
            AstSimpleName *simple_name = postfix_expression -> expression -> SimpleNameCast();
            if (simple_name)
            {
                if (simple_name -> resolution_opt)
                   read_method = simple_name -> resolution_opt -> symbol -> MethodCast();
            }
            else
            {
                AstFieldAccess *field_access = (AstFieldAccess *) postfix_expression -> expression;
                if (field_access -> resolution_opt)
                    read_method = field_access -> resolution_opt -> symbol -> MethodCast();
            }

            VariableSymbol *variable_symbol;
            if (read_method)
            {
                variable_symbol = (VariableSymbol *) read_method -> accessed_member;
                postfix_expression -> write_method = TypeSymbol::GetWriteAccessMethod(variable_symbol);
            }
            else variable_symbol = postfix_expression -> expression -> symbol -> VariableCast();
        }
    }

    return;
}


void Semantic::ProcessPLUS(AstPreUnaryExpression *expr)
{
    ProcessExpression(expr -> expression);
    expr -> expression = PromoteUnaryNumericExpression(expr -> expression);
    expr -> value = expr -> expression -> value;
    expr -> symbol = expr -> expression -> symbol;
}


void Semantic::ProcessMINUS(AstPreUnaryExpression *expr)
{
    AstIntegerLiteral *int_literal;
    AstLongLiteral *long_literal;

    if (int_literal = expr -> expression -> IntegerLiteralCast())
    {
        LiteralSymbol *literal = (LiteralSymbol *) lex_stream -> NameSymbol(int_literal -> integer_literal_token);

        expr -> value = control.int_pool.FindOrInsertNegativeInt(literal);
        if (expr -> value == &control.bad_value)
        {
            ReportSemError(SemanticError::INVALID_INT_VALUE,
                           expr -> LeftToken(),
                           expr -> RightToken());
            expr -> symbol = control.no_type;
        }
        else expr -> symbol = control.int_type;
    }
    else if (long_literal = expr -> expression -> LongLiteralCast())
    {
        LiteralSymbol *literal = (LiteralSymbol *) lex_stream -> NameSymbol(long_literal -> long_literal_token);

        expr -> value = control.long_pool.FindOrInsertNegativeLong(literal);
        if (expr -> value == &control.bad_value)
        {
            ReportSemError(SemanticError::INVALID_LONG_VALUE,
                           expr -> LeftToken(),
                           expr -> RightToken());
            expr -> symbol = control.no_type;
        }
        else expr -> symbol = control.long_type;
    }
    else
    {
        ProcessExpression(expr -> expression);

        expr -> expression = PromoteUnaryNumericExpression(expr -> expression);
        expr -> symbol = expr -> expression -> symbol;
        if (expr -> expression -> IsConstant())
        {
            TypeSymbol *type = expr -> Type();

            if (type == control.double_type)
            {
                DoubleLiteralValue *literal = (DoubleLiteralValue *) expr -> expression -> value;
                expr -> value = control.double_pool.FindOrInsert(-literal -> value);
            }
            else if (type == control.float_type)
            {
                FloatLiteralValue *literal = (FloatLiteralValue *) expr -> expression -> value;
                expr -> value = control.float_pool.FindOrInsert(-literal -> value);
            }
            else if (type == control.long_type)
            {
                LongLiteralValue *literal = (LongLiteralValue *) expr -> expression -> value;
                expr -> value = control.long_pool.FindOrInsert(-literal -> value);
            }
            else
            {
                IntLiteralValue *literal = (IntLiteralValue *) expr -> expression -> value;
                expr -> value = control.int_pool.FindOrInsert(-literal -> value);
            }
        }
    }

    return;
}


void Semantic::ProcessTWIDDLE(AstPreUnaryExpression *expr)
{
    ProcessExpression(expr -> expression);

    if (expr -> expression -> symbol != control.no_type && (! control.IsIntegral(expr -> expression -> Type())))
    {
        ReportSemError(SemanticError::TYPE_NOT_INTEGRAL,
                       expr -> expression -> LeftToken(),
                       expr -> expression -> RightToken(),
                       expr -> expression -> Type() -> Name());
        expr -> symbol = control.no_type;
    }
    else
    {
        expr -> expression = PromoteUnaryNumericExpression(expr -> expression);

        if (expr -> expression -> IsConstant())
        {
            if (expr -> expression -> Type() == control.long_type)
            {
                LongLiteralValue *literal = (LongLiteralValue *) expr -> expression -> value;
                expr -> value = control.long_pool.FindOrInsert(~literal -> value);
            }
            else // assert(expr -> expression -> Type() == control.int_type)
            {
                IntLiteralValue *literal = (IntLiteralValue *) expr -> expression -> value;
                expr -> value = control.int_pool.FindOrInsert(~literal -> value);
            }
        }
        expr -> symbol = expr -> expression -> symbol;
    }

    return;
}


void Semantic::ProcessNOT(AstPreUnaryExpression *expr)
{
    ProcessExpression(expr -> expression);

    if (expr -> expression -> symbol != control.no_type && expr -> expression -> Type() != control.boolean_type)
    {
        ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
                       expr -> expression -> LeftToken(),
                       expr -> expression -> RightToken(),
                       expr -> expression -> Type() -> Name());
        expr -> symbol = control.no_type;
    }
    else
    {
        if (expr -> expression -> IsConstant())
        {
            IntLiteralValue *literal = (IntLiteralValue *) expr -> expression -> value;
            expr -> value = control.int_pool.FindOrInsert(literal -> value ? 0 : 1);
        }
        expr -> symbol = control.boolean_type;
    }

    return;
}


void Semantic::ProcessPLUSPLUSOrMINUSMINUS(AstPreUnaryExpression *expr)
{
    ProcessExpression(expr -> expression);

    if (expr -> expression -> symbol != control.no_type)
    {
        if (! expr -> expression -> IsLeftHandSide())
        {
            ReportSemError(SemanticError::NOT_A_NUMERIC_VARIABLE,
                           expr -> expression -> LeftToken(),
                           expr -> expression -> RightToken(),
                           expr -> expression -> Type() -> Name());
            expr -> symbol = control.no_type;
        }
        else if (! control.IsNumeric(expr -> expression -> Type()))
        {
            ReportSemError(SemanticError::TYPE_NOT_NUMERIC,
                           expr -> expression -> LeftToken(),
                           expr -> expression -> RightToken(),
                           expr -> expression -> Type() -> Name());
            expr -> symbol = control.no_type;
        }
        else if (! expr -> expression -> ArrayAccessCast()) // some kind of name
        {
            MethodSymbol *read_method = NULL;
            AstSimpleName *simple_name = expr -> expression -> SimpleNameCast();
            if (simple_name)
            {
                if (simple_name -> resolution_opt)
                   read_method = simple_name -> resolution_opt -> symbol -> MethodCast();
            }
            else
            {
                AstFieldAccess *field_access = (AstFieldAccess *) expr -> expression;
                if (field_access -> resolution_opt)
                    read_method = field_access -> resolution_opt -> symbol -> MethodCast();
            }

            VariableSymbol *variable_symbol;
            if (read_method)
            {
                variable_symbol = (VariableSymbol *) read_method -> accessed_member;
                expr -> write_method = TypeSymbol::GetWriteAccessMethod(variable_symbol);
            }
            else variable_symbol = expr -> expression -> symbol -> VariableCast();
        }
    }
    expr -> symbol = expr -> expression -> symbol;

    return;
}


void Semantic::ProcessPreUnaryExpression(Ast *expr)
{
    AstPreUnaryExpression *prefix_expression = (AstPreUnaryExpression *) expr;
    (this ->* ProcessPreUnaryExpr[prefix_expression -> pre_unary_tag])(prefix_expression);

    return;
}


inline bool Semantic::CanWideningPrimitiveConvert(TypeSymbol *target_type, TypeSymbol *source_type)
{
    if (target_type == control.double_type)
         return (source_type == control.float_type || source_type == control.long_type  || source_type == control.int_type ||
                 source_type == control.char_type  || source_type == control.short_type || source_type == control.byte_type);
    else if (target_type == control.float_type)
         return (source_type == control.long_type  || source_type == control.int_type   ||
                 source_type == control.char_type  || source_type == control.short_type || source_type == control.byte_type);
    else if (target_type == control.long_type)
         return (source_type == control.int_type   || source_type == control.char_type  ||
                 source_type == control.short_type || source_type == control.byte_type);
    else if (target_type == control.int_type)
         return (source_type == control.char_type  || source_type == control.short_type || source_type == control.byte_type);
    else if (target_type == control.short_type)
         return source_type == control.byte_type;

    return false;
}


inline bool Semantic::CanNarrowingPrimitiveConvert(TypeSymbol *target_type, TypeSymbol *source_type)
{
    if (target_type == control.byte_type)
         return (source_type == control.double_type || source_type == control.float_type || source_type == control.long_type ||
                 source_type == control.int_type    || source_type == control.char_type  || source_type == control.short_type);
    else if (target_type == control.char_type)
         return (source_type == control.double_type || source_type == control.float_type || source_type == control.long_type ||
                 source_type == control.int_type    || source_type == control.short_type || source_type == control.byte_type);
    else if (target_type == control.short_type)
         return (source_type == control.double_type || source_type == control.float_type ||
                 source_type == control.long_type   || source_type == control.int_type   || source_type == control.char_type);
    else if (target_type == control.int_type)
         return (source_type == control.double_type || source_type == control.float_type || source_type == control.long_type);
    else if (target_type == control.long_type)
         return (source_type == control.double_type || source_type == control.float_type);
    else if (target_type == control.float_type)
         return source_type == control.double_type;

    return false;
}


bool Semantic::CanMethodInvocationConvert(TypeSymbol *target_type, TypeSymbol *source_type)
{
    if (target_type == control.no_type || source_type == control.no_type)
        return false;

    if (source_type -> Primitive())
    {
        if (! target_type -> Primitive())
            return false;

        return (target_type == source_type || CanWideningPrimitiveConvert(target_type, source_type));
    }
    else
    {
        if (target_type -> Primitive())
            return false;

        if (source_type -> IsArray())
        {
            if (target_type -> IsArray())
            {
                TypeSymbol *source_subtype = source_type -> ArraySubtype();
                TypeSymbol *target_subtype = target_type -> ArraySubtype();
                return (source_subtype -> Primitive() && target_subtype -> Primitive()
                                                       ? (source_subtype == target_subtype)
                                                       : CanMethodInvocationConvert(target_subtype, source_subtype));
            }
            return (target_type == control.Object() ||
                    target_type == control.Cloneable() ||
                    //
                    // TODO: This is an undocumented feature, but this fix appears to make sense. 
                    //
                    (control.option.one_one && target_type == control.Serializable() && source_type -> Implements(target_type)));
        }
        else if (source_type -> ACC_INTERFACE())
        {
            if (target_type -> ACC_INTERFACE())
                 return source_type -> IsSubinterface(target_type);
            else if (target_type != control.Object()) // target is a class type
                 return false;
        }
        else if (source_type != control.null_type) // source_type is a class
        {
            if (target_type -> IsArray())
                 return false;
            else if (target_type -> ACC_INTERFACE())
                 return source_type -> Implements(target_type);
            else if (! source_type -> IsSubclass(target_type))
                 return false;
        }
    }

    return true;
}


bool Semantic::CanAssignmentConvertReference(TypeSymbol *target_type, TypeSymbol *source_type)
{
    return (target_type == control.no_type || 
            source_type == control.no_type ||
            CanMethodInvocationConvert(target_type, source_type)
           );
}


bool Semantic::CanAssignmentConvert(TypeSymbol *target_type, AstExpression *expr)
{
    return (target_type == control.no_type || 
            expr -> symbol == control.no_type ||
            CanMethodInvocationConvert(target_type, expr -> Type()) ||
            IsIntValueRepresentableInType(expr, target_type)
           );
}


bool Semantic::CanCastConvert(TypeSymbol *target_type, TypeSymbol *source_type, LexStream::TokenIndex tok)
{
    if (source_type == target_type || source_type == control.no_type || target_type == control.no_type)
        return true;

    if (source_type -> Primitive())
    {
        if (! target_type -> Primitive())
            return false;

        return (CanWideningPrimitiveConvert(target_type, source_type) || CanNarrowingPrimitiveConvert(target_type, source_type));
    }
    else
    {
        if (target_type -> Primitive())
            return false;

        if (source_type -> IsArray())
        {
            if (target_type -> IsArray())
            {
                TypeSymbol *source_subtype = source_type -> ArraySubtype();
                TypeSymbol *target_subtype = target_type -> ArraySubtype();
                return (source_subtype -> Primitive() && target_subtype -> Primitive()
                                                       ? (source_subtype == target_subtype)
                                                       : CanCastConvert(target_subtype, source_subtype, tok));
            }
            return (target_type == control.Object() ||
                    target_type == control.Cloneable() ||
                    //
                    // TODO: This is an undocumented feature, but this fix appears to make sense. 
                    //
                    (control.option.one_one && target_type == control.Serializable() && source_type -> Implements(target_type)));
        }
        else if (source_type -> ACC_INTERFACE())
        {
            if (target_type -> ACC_INTERFACE())
            {
                if (! source_type -> expanded_method_table)
                    ComputeMethodsClosure(source_type, tok);
                if (! target_type -> expanded_method_table)
                    ComputeMethodsClosure(target_type, tok);

                //
                // Iterate over all methods in the source symbol table of the source_type interface;
                // For each such method, if the target_type contains a method with the same signature,
                // then make sure that the two methods have the same return type.
                //
                ExpandedMethodTable *source_method_table = source_type -> expanded_method_table;
                int i;
                for (i = 0; i < source_method_table -> symbol_pool.Length(); i++)
                {
                    MethodSymbol *method1 = source_method_table -> symbol_pool[i] -> method_symbol;
                    MethodShadowSymbol *method_shadow2 = target_type -> expanded_method_table
                                                                     -> FindOverloadMethodShadow(method1, (Semantic *) this, tok);
                    if (method_shadow2)
                    {
                        if (! method1 -> IsTyped())
                            method1 -> ProcessMethodSignature((Semantic *) this, tok);

                        MethodSymbol *method2 = method_shadow2 -> method_symbol;
                        if (! method2 -> IsTyped())
                            method2 -> ProcessMethodSignature((Semantic *) this, tok);
                        if (method1 -> Type() != method2 -> Type())
                            break;
                    }
                }

                return (i == source_method_table -> symbol_pool.Length()); // all the methods passed the test
            }
            else if (target_type -> ACC_FINAL() && (! target_type -> Implements(source_type)))
                 return false;
        }
        else if (source_type != control.null_type) // source_type is a class
        {
            if (target_type -> IsArray())
            {
                if (source_type != control.Object())
                    return false;
            }
            else if (target_type -> ACC_INTERFACE())
            {
                if (source_type -> ACC_FINAL() && (! source_type -> Implements(target_type)))
                    return false;
            }
            else if ((! source_type -> IsSubclass(target_type)) && (! target_type -> IsSubclass(source_type)))
                 return false;
        }
    }

    return true;
}


LiteralValue *Semantic::CastPrimitiveValue(TypeSymbol *target_type, AstExpression *expr)
{
    LiteralValue *literal_value = NULL;
    TypeSymbol *source_type = expr -> Type();

    if (target_type == source_type)
        literal_value = expr -> value;
    else if (source_type != control.no_type)
    {
        char output_string[25];
        int len;

        if (target_type == control.String())
        {
            if (source_type == control.double_type)
            {
                //
                // TODO: Check correctness !!!
                //
                DoubleLiteralValue *literal = (DoubleLiteralValue *) expr -> value;
                // sprintf(output_string, "%E", literal -> value);
                literal -> value.String(output_string);
                len = strlen(output_string);
                literal_value = control.Utf8_pool.FindOrInsert(output_string, len);
            }
            else if (source_type == control.float_type)
            {
                //
                // TODO: Check correctness !!!
                //
                FloatLiteralValue *literal = (FloatLiteralValue *) expr -> value;
                // sprintf(output_string, "%E", literal -> value);
                literal -> value.String(output_string);
                len = strlen(output_string);
                //
                // javac does not add the L suffix
                //
                // output_string[len++] = U_F;
                //
                output_string[len] = U_NULL;
                literal_value = control.Utf8_pool.FindOrInsert(output_string, len);
            }
            else if (source_type == control.long_type)
            {
                LongLiteralValue *literal = (LongLiteralValue *) expr -> value;
                literal -> value.String(output_string);
                len = strlen(output_string);
                //
                // javac does not add the L suffix
                //
                // output_string[len++] = U_L;
                //
                output_string[len] = U_NULL;
                literal_value = control.Utf8_pool.FindOrInsert(output_string, len);
            }
            else if (source_type == control.char_type)
            {
                IntLiteralValue *literal = (IntLiteralValue *) expr -> value;
                literal_value = control.Utf8_pool.FindOrInsert(literal -> value);
            }
            else if (control.IsSimpleIntegerValueType(source_type))
            {
                //
                // TODO: Check correctness !!!
                //
                IntLiteralValue *literal = (IntLiteralValue *) expr -> value;
                sprintf(output_string, "%i", literal -> value);
                len = strlen(output_string);
                literal_value = control.Utf8_pool.FindOrInsert(output_string, len);
            }
        }
        else if (target_type == control.double_type)
        {
            if (source_type == control.float_type)
            {
                FloatLiteralValue *literal = (FloatLiteralValue *) expr -> value;
                IEEEdouble value(literal -> value);
                literal_value = control.double_pool.FindOrInsert(value);
            }
            else if (source_type == control.long_type)
            {
                LongLiteralValue *literal = (LongLiteralValue *) expr -> value;
                IEEEdouble value(literal -> value);
                literal_value = control.double_pool.FindOrInsert(value);
            }
            else
            {
                IntLiteralValue *literal = (IntLiteralValue *) expr -> value;
                IEEEdouble value(literal -> value);
                literal_value = control.double_pool.FindOrInsert(value);
            }
        }
        else if (target_type == control.float_type)
        {
            if (source_type == control.double_type)
            {
                DoubleLiteralValue *literal = (DoubleLiteralValue *) expr -> value;
                IEEEfloat value(literal -> value);
                literal_value = control.float_pool.FindOrInsert(value);
            }
            else if (source_type == control.long_type)
            {
                LongLiteralValue *literal = (LongLiteralValue *) expr -> value;
                IEEEfloat value(literal -> value);
                literal_value = control.float_pool.FindOrInsert(value);
            }
            else
            {
                IntLiteralValue *literal = (IntLiteralValue *) expr -> value;
                IEEEfloat value(literal -> value);
                literal_value = control.float_pool.FindOrInsert(value);
            }
        }
        else if (target_type == control.long_type)
        {
            if (source_type == control.double_type)
            {
                DoubleLiteralValue *literal = (DoubleLiteralValue *) expr -> value;
                LongInt value(literal -> value);
                literal_value = control.long_pool.FindOrInsert(value);
            }
            else if (source_type == control.float_type)
            {
                FloatLiteralValue *literal = (FloatLiteralValue *) expr -> value;
                LongInt value(literal -> value);
                literal_value = control.long_pool.FindOrInsert(value);
            }
            else
            {
                IntLiteralValue *literal = (IntLiteralValue *) expr -> value;
                literal_value = control.long_pool.FindOrInsert((LongInt) literal -> value);
            }
        }
        else if (target_type == control.int_type)
        {
            if (source_type == control.double_type)
            {
                DoubleLiteralValue *literal = (DoubleLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((literal -> value).IntValue());
            }
            else if (source_type == control.float_type)
            {
                FloatLiteralValue *literal = (FloatLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert(literal -> value.IntValue());
            }
            else if (source_type == control.long_type)
            {
                LongLiteralValue *literal = (LongLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((int) (literal -> value).LowWord());
            }
            else literal_value = expr -> value;
        }
        else if (target_type == control.char_type)
        {
            if (source_type == control.double_type)
            {
                DoubleLiteralValue *literal = (DoubleLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((int) (u2) (literal -> value.IntValue()));
            }
            else if (source_type == control.float_type)
            {
                FloatLiteralValue *literal = (FloatLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((int) (u2) (literal -> value.IntValue()));
            }
            else if (source_type == control.long_type)
            {
                LongLiteralValue *literal = (LongLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((int) (u2) (literal -> value).LowWord());
            }
            else
            {
                IntLiteralValue *literal = (IntLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((int) (u2) literal -> value);
            }
        }
        else if (target_type == control.short_type)
        {
            if (source_type == control.double_type)
            {
                DoubleLiteralValue *literal = (DoubleLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((int) (i2) (literal -> value.IntValue()));
            }
            else if (source_type == control.float_type)
            {
                FloatLiteralValue *literal = (FloatLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((int) (i2) (literal -> value.IntValue()));
            }
            else if (source_type == control.long_type)
            {
                LongLiteralValue *literal = (LongLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((int) (i2) (literal -> value).LowWord());
            }
            else
            {
                IntLiteralValue *literal = (IntLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((int) (i2) literal -> value);
            }
        }
        else if (target_type == control.byte_type)
        {
            if (source_type == control.double_type)
            {
                DoubleLiteralValue *literal = (DoubleLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((int) (i1) (literal -> value.IntValue()));
            }
            else if (source_type == control.float_type)
            {
                FloatLiteralValue *literal = (FloatLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((int) (i1) (literal -> value.IntValue()));
            }
            else if (source_type == control.long_type)
            {
                LongLiteralValue *literal = (LongLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((int) (i1) (literal -> value).LowWord());
            }
            else
            {
                IntLiteralValue *literal = (IntLiteralValue *) expr -> value;
                literal_value = control.int_pool.FindOrInsert((int) (i1) literal -> value);
            }
        }
    }

    return literal_value;
}


//
// We only need to cast the value of constant primitive expressions.
//
inline LiteralValue *Semantic::CastValue(TypeSymbol *target_type, AstExpression *expr)
{
    return (LiteralValue *) (expr -> IsConstant() && target_type -> Primitive()
                                                   ? CastPrimitiveValue(target_type, expr)
                                                   : (expr -> value == control.NullValue() ? expr -> value : NULL));
}


void Semantic::ProcessCastExpression(Ast *expr)
{
    AstCastExpression *cast_expression = (AstCastExpression *) expr;

    //
    // This operation may throw ClassCastException
    //
    SymbolSet *exception_set = TryExceptionTableStack().Top();
    if (exception_set)
    {
        exception_set -> AddElement(control.RuntimeException());
        exception_set -> AddElement(control.Error());
    }

    ProcessExpression(cast_expression -> expression);

    TypeSymbol *source_type = cast_expression -> expression -> Type();

    //
    // Recall that the type is optional only when the compiler inserts
    // a CAST conversion node into the program.
    //
    AstPrimitiveType *primitive_type = cast_expression -> type_opt -> PrimitiveTypeCast();
    TypeSymbol *target_type;
    if (primitive_type)
         target_type = FindPrimitiveType(primitive_type);
    else if (cast_expression -> type_opt -> IsName())
         target_type = MustFindType(cast_expression -> type_opt);
    else
    {
        ReportSemError(SemanticError::INVALID_CAST_TYPE,
                       cast_expression -> type_opt -> LeftToken(),
                       cast_expression -> type_opt -> RightToken());
        cast_expression -> symbol = control.no_type;

        return;
    }

    int num_dimensions = cast_expression -> NumBrackets();
    target_type = (num_dimensions == 0 ? target_type : target_type -> GetArrayType((Semantic *) this, num_dimensions));
    
    if (CanAssignmentConvert(target_type, cast_expression -> expression))
    {
        cast_expression -> symbol = target_type;
        cast_expression -> value = CastValue(target_type, cast_expression -> expression);
    }
    else if (CanCastConvert(target_type, source_type, cast_expression -> right_parenthesis_token_opt))
    {
        cast_expression -> kind = Ast::CHECK_AND_CAST;
        cast_expression -> symbol = target_type;
        cast_expression -> value = CastValue(target_type, cast_expression -> expression);
    }
    else
    {
        ReportSemError(SemanticError::INVALID_CAST_CONVERSION,
                       cast_expression -> expression -> LeftToken(),
                       cast_expression -> expression -> RightToken(),
                       source_type -> Name(),
                       target_type -> Name());
        cast_expression -> symbol = control.no_type;
    }

    return;
}


AstExpression *Semantic::ConvertToType(AstExpression *expr, TypeSymbol *type)
{
    if (expr -> Type() == control.null_type)
        return expr;

    LexStream::TokenIndex loc = expr -> LeftToken();

    AstCastExpression *result = compilation_unit -> ast_pool -> GenCastExpression();
    result -> left_parenthesis_token_opt = loc;
    result -> type_opt = NULL;
    result -> right_parenthesis_token_opt = loc;
    result -> expression = expr;

    result -> symbol = type;
    result -> value = CastValue(type, expr);

    return result;
}


AstExpression *Semantic::PromoteUnaryNumericExpression(AstExpression *unary_expression)
{
    TypeSymbol *type = unary_expression -> Type();

    if (type == control.no_type)
        return unary_expression;

    if (! control.IsNumeric(type))
    {
       ReportSemError(SemanticError::TYPE_NOT_NUMERIC,
                      unary_expression -> LeftToken(),
                      unary_expression -> RightToken(),
                      type -> Name());
        unary_expression -> symbol = control.no_type;
        return unary_expression;
    }

    return ((type == control.byte_type || type == control.short_type || type == control.char_type)
                                                ? ConvertToType(unary_expression, control.int_type)
                                                : unary_expression);
}


void Semantic::BinaryNumericPromotion(AstBinaryExpression *binary_expression)
{
    AstExpression *left_expr = binary_expression -> left_expression;
    AstExpression *right_expr = binary_expression -> right_expression;

    TypeSymbol *left_type  = left_expr -> Type(),
               *right_type = right_expr -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
    {
        binary_expression -> symbol = control.no_type;
        return;
    }

    if (! control.IsNumeric(left_type))
    {
       ReportSemError(SemanticError::TYPE_NOT_NUMERIC,
                      left_expr -> LeftToken(),
                      left_expr -> RightToken(),
                      left_type -> Name());
        binary_expression -> symbol = control.no_type;
        return;
    }
    else if (! control.IsNumeric(right_type))
    {
       ReportSemError(SemanticError::TYPE_NOT_NUMERIC,
                      right_expr -> LeftToken(),
                      right_expr -> RightToken(),
                      right_type -> Name());
        binary_expression -> symbol = control.no_type;
        return;
    }

    if (left_type == control.double_type)
    {
        if (right_type != control.double_type)
            binary_expression -> right_expression = ConvertToType(binary_expression -> right_expression, control.double_type);
        binary_expression -> symbol = control.double_type;
    }
    else if (right_type == control.double_type)
    {
        if (left_type != control.double_type)
            binary_expression -> left_expression = ConvertToType(binary_expression -> left_expression, control.double_type);
        binary_expression -> symbol = control.double_type;
    }
    else if (left_type == control.float_type)
    {
        if (right_type != control.float_type)
            binary_expression -> right_expression = ConvertToType(binary_expression -> right_expression, control.float_type);
        binary_expression -> symbol = control.float_type;
    }
    else if (right_type == control.float_type)
    {
        if (left_type != control.float_type)
            binary_expression -> left_expression = ConvertToType(binary_expression -> left_expression, control.float_type);
        binary_expression -> symbol = control.float_type;
    }
    else if (left_type == control.long_type)
    {
        if (right_type != control.long_type)
            binary_expression -> right_expression = ConvertToType(binary_expression -> right_expression, control.long_type);
        binary_expression -> symbol = control.long_type;
    }
    else if (right_type == control.long_type)
    {
        if (left_type != control.long_type)
            binary_expression -> left_expression = ConvertToType(binary_expression -> left_expression, control.long_type);
        binary_expression -> symbol = control.long_type;
    }
    else
    {
        if (left_type != control.int_type)
            binary_expression -> left_expression = ConvertToType(binary_expression -> left_expression, control.int_type);
        if (right_type != control.int_type)
            binary_expression -> right_expression = ConvertToType(binary_expression -> right_expression, control.int_type);
        binary_expression -> symbol = control.int_type;
    }

    return;
}


void Semantic::BinaryNumericPromotion(AstAssignmentExpression *assignment_expression)
{
    AstExpression *left_expr = assignment_expression -> left_hand_side;
    AstExpression *right_expr = assignment_expression -> expression;

    TypeSymbol *left_type  = left_expr -> Type(),
               *right_type = right_expr -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
        return;

    if (! control.IsNumeric(left_type))
    {
       ReportSemError(SemanticError::TYPE_NOT_NUMERIC,
                      left_expr -> LeftToken(),
                      left_expr -> RightToken(),
                      left_type -> Name());
        return;
    }
    else if (! control.IsNumeric(right_type))
    {
       ReportSemError(SemanticError::TYPE_NOT_NUMERIC,
                      right_expr -> LeftToken(),
                      right_expr -> RightToken(),
                      right_type -> Name());
        return;
    }

    if (left_type == control.double_type)
    {
        if (right_type != control.double_type)
            assignment_expression -> expression = ConvertToType(assignment_expression -> expression, control.double_type);
    }
    else if (right_type == control.double_type)
    {
        if (left_type != control.double_type)
            assignment_expression -> left_hand_side = ConvertToType(assignment_expression -> left_hand_side, control.double_type);
    }   
    else if (left_type == control.float_type)
    {
        if (right_type != control.float_type)
            assignment_expression -> expression = ConvertToType(assignment_expression -> expression, control.float_type);
    }
    else if (right_type == control.float_type)
    {
        if (left_type != control.float_type)
            assignment_expression -> left_hand_side = ConvertToType(assignment_expression -> left_hand_side, control.float_type);
    }
    else if (left_type == control.long_type)
    {
        if (right_type != control.long_type)
            assignment_expression -> expression = ConvertToType(assignment_expression -> expression, control.long_type);
    }
    else if (right_type == control.long_type)
    {
        if (left_type != control.long_type)
            assignment_expression -> left_hand_side = ConvertToType(assignment_expression -> left_hand_side, control.long_type);
    }
    else
    {
        if (left_type != control.int_type)
            assignment_expression -> left_hand_side = ConvertToType(assignment_expression -> left_hand_side, control.int_type);
        if (right_type != control.int_type)
            assignment_expression -> expression = ConvertToType(assignment_expression -> expression, control.int_type);
    }

    return;
}


void Semantic::BinaryNumericPromotion(AstConditionalExpression *conditional_expression)
{
    AstExpression *left_expr = conditional_expression -> true_expression;
    AstExpression *right_expr = conditional_expression -> false_expression;

    TypeSymbol *left_type  = left_expr -> Type(),
               *right_type = right_expr -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
    {
        conditional_expression -> symbol = control.no_type;
        return;
    }

    if (! control.IsNumeric(left_type))
    {
       ReportSemError(SemanticError::TYPE_NOT_NUMERIC,
                      left_expr -> LeftToken(),
                      left_expr -> RightToken(),
                      left_type -> Name());
        conditional_expression -> symbol = control.no_type;
        return;
    }
    else if (! control.IsNumeric(right_type))
    {
       ReportSemError(SemanticError::TYPE_NOT_NUMERIC,
                      right_expr -> LeftToken(),
                      right_expr -> RightToken(),
                      right_type -> Name());
        conditional_expression -> symbol = control.no_type;
        return;
    }

    if (left_type == control.double_type)
    {
        if (right_type != control.double_type)
            conditional_expression -> false_expression =
                        ConvertToType(conditional_expression -> false_expression, control.double_type);
        conditional_expression -> symbol = control.double_type;
    }
    else if (right_type == control.double_type)
    {
        if (left_type != control.double_type)
            conditional_expression -> true_expression =
                        ConvertToType(conditional_expression -> true_expression, control.double_type);
        conditional_expression -> symbol = control.double_type;
    }
    else if (left_type == control.float_type)
    {
        if (right_type != control.float_type)
            conditional_expression -> false_expression =
                        ConvertToType(conditional_expression -> false_expression, control.float_type);
        conditional_expression -> symbol = control.float_type;
    }
    else if (right_type == control.float_type)
    {
        if (left_type != control.float_type)
            conditional_expression -> true_expression =
                        ConvertToType(conditional_expression -> true_expression, control.float_type);
        conditional_expression -> symbol = control.float_type;
    }
    else if (left_type == control.long_type)
    {
        if (right_type != control.long_type)
            conditional_expression -> false_expression =
                        ConvertToType(conditional_expression -> false_expression, control.long_type);
        conditional_expression -> symbol = control.long_type;
    }
    else if (right_type == control.long_type)
    {
        if (left_type != control.long_type)
            conditional_expression -> true_expression = ConvertToType(conditional_expression -> true_expression, control.long_type);
        conditional_expression -> symbol = control.long_type;
    }
    else
    {
        if (left_type != control.int_type)
            conditional_expression -> true_expression = ConvertToType(conditional_expression -> true_expression, control.int_type);
        if (right_type != control.int_type)
            conditional_expression -> false_expression =
                        ConvertToType(conditional_expression -> false_expression, control.int_type);
        conditional_expression -> symbol = control.int_type;
    }

    return;
}


void Semantic::ProcessPLUS(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
        expr -> symbol = control.no_type;
    else if (left_type == control.String() || right_type == control.String())
    {
        //
        // This operation may throw OutOfMemoryException
        //
        SymbolSet *exception_set = TryExceptionTableStack().Top();
        if (exception_set)
        {
            exception_set -> AddElement(control.RuntimeException());
            exception_set -> AddElement(control.Error());
        }

        if (left_type != control.String())
        {
            AddStringConversionDependence(left_type, expr -> binary_operator_token);
            AstExpression *left_expression = expr -> left_expression;
            if (left_type == control.void_type)
                ReportSemError(SemanticError::VOID_TO_STRING,
                               left_expression -> LeftToken(),
                               left_expression -> RightToken());
            expr -> left_expression = ConvertToType(left_expression, control.String());
            if (left_expression -> IsConstant())
                expr -> left_expression -> value = CastPrimitiveValue(control.String(), left_expression);
        }
        else if (right_type != control.String())
        {
            AddStringConversionDependence(right_type, expr -> binary_operator_token);
            AstExpression *right_expression = expr -> right_expression;
            if (right_type == control.void_type)
                ReportSemError(SemanticError::VOID_TO_STRING,
                               right_expression -> LeftToken(),
                               right_expression -> RightToken());
            expr -> right_expression = ConvertToType(right_expression, control.String());
            if (right_expression -> IsConstant())
                expr -> right_expression -> value = CastPrimitiveValue(control.String(), right_expression);
        }
        AddDependence(ThisType(), control.StringBuffer(), expr -> binary_operator_token);

        //
        // If both subexpressions are strings constants, identify the result as
        // as a string constant, but do not perform the concatenation here. The
        // reason being that if we have a long expression of the form
        //
        //  s1 + s2 + ... + sn
        //
        // where each subexpression s(i) is a string constant, we want to perform
        // one concatenation and enter a single result into the constant pool instead
        // of n-1 subresults. See CheckStringConstant in lookup.cpp.
        //

        expr -> symbol = control.String();
    }
    else
    {
        BinaryNumericPromotion(expr);

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
             if (expr -> Type() == control.double_type)
             {
                 DoubleLiteralValue *left = (DoubleLiteralValue *) expr -> left_expression -> value;
                 DoubleLiteralValue *right = (DoubleLiteralValue *) expr -> right_expression -> value;

                 expr -> value = control.double_pool.FindOrInsert(left -> value + right -> value);
             }
             else if (expr -> Type() == control.float_type)
             {
                 FloatLiteralValue *left = (FloatLiteralValue *) expr -> left_expression -> value;
                 FloatLiteralValue *right = (FloatLiteralValue *) expr -> right_expression -> value;

                 expr -> value = control.float_pool.FindOrInsert(left -> value + right -> value);
             }
             else if (expr -> Type() == control.long_type)
             {
                 LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                 LongLiteralValue *right = (LongLiteralValue *) expr -> right_expression -> value;

                 expr -> value = control.long_pool.FindOrInsert(left -> value + right -> value);
             }
             else // assert(expr -> Type() == control.int_type)
             {
                 IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                 IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                 expr -> value = control.int_pool.FindOrInsert(left -> value + right -> value);
             }
        }
    }

    return;
}


void Semantic::ProcessLEFT_SHIFT(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
        expr -> symbol = control.no_type;
    else if (! control.IsIntegral(left_type))
    {
        ReportSemError(SemanticError::TYPE_NOT_INTEGRAL,
                       expr -> left_expression -> LeftToken(),
                       expr -> left_expression -> RightToken(),
                       left_type -> Name());
        expr -> symbol = control.no_type;
    }
    else if (! control.IsIntegral(right_type))
    {
        ReportSemError(SemanticError::TYPE_NOT_INTEGRAL,
                       expr -> right_expression -> LeftToken(),
                       expr -> right_expression -> RightToken(),
                       right_type -> Name());
        expr -> symbol = control.no_type;
    }
    else
    {
        expr -> left_expression  = PromoteUnaryNumericExpression(expr -> left_expression);
        expr -> right_expression = PromoteUnaryNumericExpression(expr -> right_expression);
        if (expr -> right_expression -> Type() == control.long_type)
            expr -> right_expression = ConvertToType(expr -> right_expression, control.int_type);
        expr -> symbol = expr -> left_expression -> symbol;

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
            if (expr -> Type() == control.long_type)
            {
                LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.long_pool.FindOrInsert(left -> value << (right -> value & 0x3F));
            }
            else // assert(expr -> Type() == control.int_type)
            {
                IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value << (0x1F & right -> value));
            }
        }
    }

    return;
}


void Semantic::ProcessRIGHT_SHIFT(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
        expr -> symbol = control.no_type;
    else if (! control.IsIntegral(left_type))
    {
        ReportSemError(SemanticError::TYPE_NOT_INTEGRAL,
                       expr -> left_expression -> LeftToken(),
                       expr -> left_expression -> RightToken(),
                       left_type -> Name());
        expr -> symbol = control.no_type;
    }
    else if (! control.IsIntegral(right_type))
    {
        ReportSemError(SemanticError::TYPE_NOT_INTEGRAL,
                       expr -> right_expression -> LeftToken(),
                       expr -> right_expression -> RightToken(),
                       right_type -> Name());
        expr -> symbol = control.no_type;
    }
    else
    {
        expr -> left_expression  = PromoteUnaryNumericExpression(expr -> left_expression);
        expr -> right_expression = PromoteUnaryNumericExpression(expr -> right_expression);
        if (expr -> right_expression -> Type() == control.long_type)
            expr -> right_expression = ConvertToType(expr -> right_expression, control.int_type);
        expr -> symbol = expr -> left_expression -> symbol;

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
            if (expr -> Type() == control.long_type)
            {
                LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.long_pool.FindOrInsert(left -> value >> (right -> value & 0x3F));
            }
            else // assert(expr -> Type() == control.int_type)
            {
                IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value >> (0x1F & right -> value));
            }
        }
    }

    return;
}


void Semantic::ProcessUNSIGNED_RIGHT_SHIFT(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
        expr -> symbol = control.no_type;
    else if (! control.IsIntegral(left_type))
    {
        ReportSemError(SemanticError::TYPE_NOT_INTEGRAL,
                       expr -> left_expression -> LeftToken(),
                       expr -> left_expression -> RightToken(),
                       left_type -> Name());
        expr -> symbol = control.no_type;
    }
    else if (! control.IsIntegral(right_type))
    {
        ReportSemError(SemanticError::TYPE_NOT_INTEGRAL,
                       expr -> right_expression -> LeftToken(),
                       expr -> right_expression -> RightToken(),
                       right_type -> Name());
        expr -> symbol = control.no_type;
    }
    else
    {
        expr -> left_expression  = PromoteUnaryNumericExpression(expr -> left_expression);
        expr -> right_expression = PromoteUnaryNumericExpression(expr -> right_expression);
        if (expr -> right_expression -> Type() == control.long_type)
            expr -> right_expression = ConvertToType(expr -> right_expression, control.int_type);
        expr -> symbol = expr -> left_expression -> symbol;

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
            if (expr -> Type() == control.long_type)
            {
                LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;
                int right_value = right -> value & 0x3F;

                LongInt value = left -> value >> right_value;
                if (left -> value < 0)
                    value += (LongInt(2) << (63 - right_value));
                expr -> value = control.long_pool.FindOrInsert(value);
            }
            else // assert(expr -> Type() == control.int_type)
            {
                IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                int value = left -> value >> (0x1F & right -> value);
                if (left -> value < 0)
                     value += (2 << (31 - (0x1F & right -> value)));
                expr -> value = control.int_pool.FindOrInsert(value);
            }
        }
    }

    return;
}


void Semantic::ProcessLESS(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type != control.no_type && right_type != control.no_type)
    {
        BinaryNumericPromotion(expr);

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
            if (expr -> Type() == control.double_type)
            {
                DoubleLiteralValue *left = (DoubleLiteralValue *) expr -> left_expression -> value;
                DoubleLiteralValue *right = (DoubleLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value < right -> value ? 1 : 0);
            }
            else if (expr -> Type() == control.float_type)
            {
                FloatLiteralValue *left = (FloatLiteralValue *) expr -> left_expression -> value;
                FloatLiteralValue *right = (FloatLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value < right -> value ? 1 : 0);
            }
            else if (expr -> Type() == control.long_type)
           {
                LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                LongLiteralValue *right = (LongLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value < right -> value ? 1 : 0);
            }
            else // assert(expr -> Type() == control.int_type)
            {
                IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value < right -> value ? 1 : 0);
            }
        }
    }

    expr -> symbol = control.boolean_type;

    return;
}


void Semantic::ProcessGREATER(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type != control.no_type && right_type != control.no_type)
    {
        BinaryNumericPromotion(expr);

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
            if (expr -> Type() == control.double_type)
            {
                DoubleLiteralValue *left = (DoubleLiteralValue *) expr -> left_expression -> value;
                DoubleLiteralValue *right = (DoubleLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value > right -> value ? 1 : 0);
            }
            else if (expr -> Type() == control.float_type)
            {
                FloatLiteralValue *left = (FloatLiteralValue *) expr -> left_expression -> value;
                FloatLiteralValue *right = (FloatLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value > right -> value ? 1 : 0);
            }
            else if (expr -> Type() == control.long_type)
            {
                LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                LongLiteralValue *right = (LongLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value > right -> value ? 1 : 0);
            }
            else // assert(expr -> Type() == control.int_type)
            {
                IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value > right -> value ? 1 : 0);
            }
        }
    }

    expr -> symbol = control.boolean_type;

    return;
}


void Semantic::ProcessLESS_EQUAL(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type != control.no_type && right_type != control.no_type)
    {
        BinaryNumericPromotion(expr);

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
            if (expr -> Type() == control.double_type)
            {
                DoubleLiteralValue *left = (DoubleLiteralValue *) expr -> left_expression -> value;
                DoubleLiteralValue *right = (DoubleLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value <= right -> value ? 1 : 0);
            }
            else if (expr -> Type() == control.float_type)
            {
                FloatLiteralValue *left = (FloatLiteralValue *) expr -> left_expression -> value;
                FloatLiteralValue *right = (FloatLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value <= right -> value ? 1 : 0);
            }
            else if (expr -> Type() == control.long_type)
            {
                LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                LongLiteralValue *right = (LongLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value <= right -> value ? 1 : 0);
            }
            else // assert(expr -> Type() == control.int_type)
            {
                IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value <= right -> value ? 1 : 0);
            }
        }
    }

    expr -> symbol = control.boolean_type;

    return;
}


void Semantic::ProcessGREATER_EQUAL(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type != control.no_type && right_type != control.no_type)
    {
        BinaryNumericPromotion(expr);

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
            if (expr -> Type() == control.double_type)
            {
                DoubleLiteralValue *left = (DoubleLiteralValue *) expr -> left_expression -> value;
                DoubleLiteralValue *right = (DoubleLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value >= right -> value ? 1 : 0);
            }
            else if (expr -> Type() == control.float_type)
            {
                FloatLiteralValue *left = (FloatLiteralValue *) expr -> left_expression -> value;
                FloatLiteralValue *right = (FloatLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value >= right -> value ? 1 : 0);
            }
            else if (expr -> Type() == control.long_type)
            {
                LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                LongLiteralValue *right = (LongLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value >= right -> value ? 1 : 0);
            }
            else // assert(expr -> Type() == control.int_type)
            {
                IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value >= right -> value ? 1 : 0);
            }
        }
    }

    expr -> symbol = control.boolean_type;

    return;
}


void Semantic::ProcessAND(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
        expr -> symbol = control.no_type;
    else
    {
        if (left_type == control.boolean_type && right_type == control.boolean_type)
             expr -> symbol = control.boolean_type;
        else
        {
            BinaryNumericPromotion(expr);

            TypeSymbol *expr_type = expr -> Type();

            if (expr_type != control.no_type)
            {
                if (! control.IsIntegral(expr_type))
                {
                    ReportSemError(SemanticError::TYPE_NOT_INTEGRAL,
                                   expr -> LeftToken(),
                                   expr -> RightToken(),
                                   expr_type -> Name());
                    expr -> symbol = control.no_type;
                }
                else if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
                {
                    if (expr_type == control.long_type)
                    {
                        LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                        LongLiteralValue *right = (LongLiteralValue *) expr -> right_expression -> value;

                        expr -> value = control.long_pool.FindOrInsert(left -> value & right -> value);
                    }
                    else // assert(expr_type == control.int_type)
                    {
                        IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                        IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                        expr -> value = control.int_pool.FindOrInsert(left -> value & right -> value);
                    }
                }
            }
        }
    }

    return;
}


void Semantic::ProcessXOR(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
        expr -> symbol = control.no_type;
    else
    {
        if (left_type == control.boolean_type && right_type == control.boolean_type)
             expr -> symbol = control.boolean_type;
        else
        {
            BinaryNumericPromotion(expr);

            TypeSymbol *expr_type = expr -> Type();

            if (expr_type != control.no_type)
            {
                if (! control.IsIntegral(expr_type))
                {
                    ReportSemError(SemanticError::TYPE_NOT_INTEGRAL,
                                   expr -> LeftToken(),
                                   expr -> RightToken(),
                                   expr_type -> Name());
                    expr -> symbol = control.no_type;
                }
                else if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
                {
                    if (expr_type == control.long_type)
                    {
                        LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                        LongLiteralValue *right = (LongLiteralValue *) expr -> right_expression -> value;

                        expr -> value = control.long_pool.FindOrInsert(left -> value ^ right -> value);
                    }
                    else // assert(expr_type == control.int_type)
                    {
                        IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                        IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                        expr -> value = control.int_pool.FindOrInsert(left -> value ^ right -> value);
                    }
                }
            }
        }
    }

    return;
}


void Semantic::ProcessIOR(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
        expr -> symbol = control.no_type;
    else
    {
        if (left_type == control.boolean_type && right_type == control.boolean_type)
             expr -> symbol = control.boolean_type;
        else
        {
            BinaryNumericPromotion(expr);

            TypeSymbol *expr_type = expr -> Type();

            if (expr_type != control.no_type)
            {
                if (! control.IsIntegral(expr_type))
                {
                    ReportSemError(SemanticError::TYPE_NOT_INTEGRAL,
                                   expr -> LeftToken(),
                                   expr -> RightToken(),
                                   expr_type -> Name());
                    expr -> symbol = control.no_type;
                }
                else if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
                {
                    if (expr_type == control.long_type)
                    {
                        LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                        LongLiteralValue *right = (LongLiteralValue *) expr -> right_expression -> value;

                        expr -> value = control.long_pool.FindOrInsert(left -> value | right -> value);
                    }
                    else // assert(expr_type == control.int_type)
                    {
                        IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                        IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                        expr -> value = control.int_pool.FindOrInsert(left -> value | right -> value);
                    }
                }
            }
        }
    }

    return;
}


void Semantic::ProcessAND_AND(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type != control.no_type && right_type != control.no_type)
    {
        if (left_type != control.boolean_type)
        {
            ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
                           expr -> left_expression -> LeftToken(),
                           expr -> left_expression -> RightToken(),
                           left_type -> Name());
        }
        else if (right_type != control.boolean_type)
        {
            ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
                           expr -> right_expression -> LeftToken(),
                           expr -> right_expression -> RightToken(),
                           right_type -> Name());
        }
        else if (expr -> left_expression -> IsConstant())
        {
            IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
            if (! left -> value)
                expr -> value = control.int_pool.FindOrInsert(0);
            else if (expr -> right_expression -> IsConstant())
            {
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;
                expr -> value = control.int_pool.FindOrInsert(left -> value && right -> value ? 1 : 0);
            }
        }
    }

    expr -> symbol = control.boolean_type;

    return;
}


void Semantic::ProcessOR_OR(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type != control.no_type && right_type != control.no_type)
    {
        if (left_type != control.boolean_type)
        {
            ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
                           expr -> left_expression -> LeftToken(),
                           expr -> left_expression -> RightToken(),
                           left_type -> Name());
        }
        else if (right_type != control.boolean_type)
        {
            ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
                           expr -> right_expression -> LeftToken(),
                           expr -> right_expression -> RightToken(),
                           right_type -> Name());
        }
        else if (expr -> left_expression -> IsConstant())
        {
            IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
            if (left -> value)
                expr -> value = control.int_pool.FindOrInsert(1);
            else if (expr -> right_expression -> IsConstant())
            {
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;
                expr -> value = control.int_pool.FindOrInsert(left -> value || right -> value ? 1 : 0);
            }
        }
    }

    expr -> symbol = control.boolean_type;

    return;
}


void Semantic::ProcessEQUAL_EQUAL(AstBinaryExpression *expr)
{
    ProcessExpressionOrStringConstant(expr -> left_expression);
    ProcessExpressionOrStringConstant(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type != control.no_type && right_type != control.no_type)
    {
        if (left_type != right_type)
        {
            if (left_type -> Primitive() && right_type -> Primitive())
                 BinaryNumericPromotion(expr);
            else if (CanCastConvert(left_type, right_type, expr -> binary_operator_token))
                 expr -> right_expression = ConvertToType(expr -> right_expression, left_type);
            else if (CanCastConvert(right_type, left_type, expr -> binary_operator_token))
                 expr -> left_expression = ConvertToType(expr -> left_expression, right_type);
            else
            {
                ReportSemError(SemanticError::INCOMPATIBLE_TYPE_FOR_BINARY_EXPRESSION,
                               expr -> LeftToken(),
                               expr -> RightToken(),
                               expr -> left_expression -> Type() -> ContainingPackage() -> PackageName(),
                               expr -> left_expression -> Type() -> ExternalName(),
                               expr -> right_expression -> Type() -> ContainingPackage() -> PackageName(),
                               expr -> right_expression -> Type() -> ExternalName());
            }
        }
        else 
        {
            if (left_type == control.void_type)
                ReportSemError(SemanticError::VOID_TYPE_IN_EQUALITY_EXPRESSION,
                               expr -> LeftToken(),
                               expr -> RightToken(),
                               expr -> left_expression -> Type() -> Name(),
                               expr -> right_expression -> Type() -> Name());
            expr -> symbol = left_type;
        }

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
            LiteralValue *left = expr -> left_expression -> value;
            LiteralValue *right = expr -> right_expression -> value;

            if (expr -> Type() == control.double_type)
            {
                DoubleLiteralValue *left = (DoubleLiteralValue *) expr -> left_expression -> value;
                DoubleLiteralValue *right = (DoubleLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value == right -> value ? 1 : 0);
            }
            else if (expr -> Type() == control.float_type)
            {
                FloatLiteralValue *left = (FloatLiteralValue *) expr -> left_expression -> value;
                FloatLiteralValue *right = (FloatLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value == right -> value ? 1 : 0);
            }
            else expr -> value = control.int_pool.FindOrInsert(left == right ? 1 : 0);
        }
    }

    expr -> symbol = control.boolean_type;

    return;
}


void Semantic::ProcessNOT_EQUAL(AstBinaryExpression *expr)
{
    ProcessExpressionOrStringConstant(expr -> left_expression);
    ProcessExpressionOrStringConstant(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type != control.no_type && right_type != control.no_type)
    {
        if (left_type != right_type)
        {
            if (left_type -> Primitive() && right_type -> Primitive())
                 BinaryNumericPromotion(expr);
            else if (CanCastConvert(left_type, right_type, expr -> binary_operator_token))
                 expr -> right_expression = ConvertToType(expr -> right_expression, left_type);
            else if (CanCastConvert(right_type, left_type, expr -> binary_operator_token))
                 expr -> left_expression = ConvertToType(expr -> left_expression, right_type);
            else
            {
                ReportSemError(SemanticError::INCOMPATIBLE_TYPE_FOR_BINARY_EXPRESSION,
                               expr -> LeftToken(),
                               expr -> RightToken(),
                               expr -> left_expression -> Type() -> ContainingPackage() -> PackageName(),
                               expr -> left_expression -> Type() -> ExternalName(),
                               expr -> right_expression -> Type() -> ContainingPackage() -> PackageName(),
                               expr -> right_expression -> Type() -> ExternalName());
            }
        }
        else 
        {
            if (left_type == control.void_type)
                ReportSemError(SemanticError::VOID_TYPE_IN_EQUALITY_EXPRESSION,
                               expr -> LeftToken(),
                               expr -> RightToken());
            expr -> symbol = left_type;
        }

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
            LiteralValue *left = expr -> left_expression -> value;
            LiteralValue *right = expr -> right_expression -> value;

            if (expr -> Type() == control.double_type)
            {
                DoubleLiteralValue *left = (DoubleLiteralValue *) expr -> left_expression -> value;
                DoubleLiteralValue *right = (DoubleLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value != right -> value ? 1 : 0);
            }
            else if (expr -> Type() == control.float_type)
            {
                FloatLiteralValue *left = (FloatLiteralValue *) expr -> left_expression -> value;
                FloatLiteralValue *right = (FloatLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value != right -> value ? 1 : 0);
            }
            else expr -> value = control.int_pool.FindOrInsert(left != right ? 1 : 0);
        }
    }

    expr -> symbol = control.boolean_type;

    return;
}


void Semantic::ProcessSTAR(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
        expr -> symbol = control.no_type;
    else
    {
        BinaryNumericPromotion(expr);

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
            if (expr -> Type() == control.double_type)
            {
                DoubleLiteralValue *left = (DoubleLiteralValue *) expr -> left_expression -> value;
                DoubleLiteralValue *right = (DoubleLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.double_pool.FindOrInsert(left -> value * right -> value);
            }
            else if (expr -> Type() == control.float_type)
            {
                FloatLiteralValue *left = (FloatLiteralValue *) expr -> left_expression -> value;
                FloatLiteralValue *right = (FloatLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.float_pool.FindOrInsert(left -> value * right -> value);
            }
            else if (expr -> Type() == control.long_type)
            {
                LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                LongLiteralValue *right = (LongLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.long_pool.FindOrInsert(left -> value * right -> value);
            }
            else if (expr -> Type() == control.int_type)
            {
                IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value * right -> value);
            }
        }
    }

    return;
}


void Semantic::ProcessMINUS(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
        expr -> symbol = control.no_type;
    else
    {
        BinaryNumericPromotion(expr);

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
            if (expr -> Type() == control.double_type)
            {
                DoubleLiteralValue *left = (DoubleLiteralValue *) expr -> left_expression -> value;
                DoubleLiteralValue *right = (DoubleLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.double_pool.FindOrInsert(left -> value - right -> value);
            }
            else if (expr -> Type() == control.float_type)
            {
                FloatLiteralValue *left = (FloatLiteralValue *) expr -> left_expression -> value;
                FloatLiteralValue *right = (FloatLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.float_pool.FindOrInsert(left -> value - right -> value);
            }
            else if (expr -> Type() == control.long_type)
            {
                LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                LongLiteralValue *right = (LongLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.long_pool.FindOrInsert(left -> value - right -> value);
            }
            else if (expr -> Type() == control.int_type)
            {
                IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                expr -> value = control.int_pool.FindOrInsert(left -> value - right -> value);
            }
        }
    }

    return;
}


void Semantic::ProcessSLASH(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
        expr -> symbol = control.no_type;
    else
    {
        BinaryNumericPromotion(expr);

        //
        // This operation may throw ArithmeticException
        //
        SymbolSet *exception_set = TryExceptionTableStack().Top();
        if (exception_set)
        {
            exception_set -> AddElement(control.RuntimeException());
            exception_set -> AddElement(control.Error());
        }

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
             if (expr -> Type() == control.double_type)
             {
                 DoubleLiteralValue *left = (DoubleLiteralValue *) expr -> left_expression -> value;
                 DoubleLiteralValue *right = (DoubleLiteralValue *) expr -> right_expression -> value;

                 expr -> value = control.double_pool.FindOrInsert(left -> value / right -> value);
             }
             else if (expr -> Type() == control.float_type)
             {
                 FloatLiteralValue *left = (FloatLiteralValue *) expr -> left_expression -> value;
                 FloatLiteralValue *right = (FloatLiteralValue *) expr -> right_expression -> value;

                 expr -> value = control.float_pool.FindOrInsert(left -> value / right -> value);
             }
             else if (expr -> Type() == control.long_type)
             {
                 LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                 LongLiteralValue *right = (LongLiteralValue *) expr -> right_expression -> value;

                 if (right -> value == 0)
                 {
                     ReportSemError(SemanticError::ZERO_DIVIDE,
                                    expr -> LeftToken(),
                                    expr -> RightToken());
                 }
                 else expr -> value = control.long_pool.FindOrInsert(left -> value / right -> value);
             }
             else if (expr -> Type() == control.int_type)
             {
                 IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                 IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                 if (right -> value == 0)
                 {
                     ReportSemError(SemanticError::ZERO_DIVIDE,
                                    expr -> LeftToken(),
                                    expr -> RightToken());
                 }
//
// There is a bug in the intel hardware where if one tries to compute ((2**32-1) / -1), he gets a ZeroDivide exception.
// Thus, instead of using the straightforward code below, we use the short-circuited one that follows:
//
//                 else expr -> value = control.int_pool.FindOrInsert(left -> value / right -> value);
//
                 else expr -> value = control.int_pool.FindOrInsert(right -> value == -1 ? -(left -> value)
                                                                                         : left -> value / right -> value);
             }
        }
    }

    return;
}


void Semantic::ProcessMOD(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type == control.no_type || right_type == control.no_type)
        expr -> symbol = control.no_type;
    else
    {
        BinaryNumericPromotion(expr);

        //
        // This operation may throw ArithmeticException
        //
        SymbolSet *exception_set = TryExceptionTableStack().Top();
        if (exception_set)
        {
            exception_set -> AddElement(control.RuntimeException());
            exception_set -> AddElement(control.Error());
        }

        if (expr -> left_expression -> IsConstant() && expr -> right_expression -> IsConstant())
        {
             if (expr -> Type() == control.double_type)
             {
                 DoubleLiteralValue *left = (DoubleLiteralValue *) expr -> left_expression -> value;
                 DoubleLiteralValue *right = (DoubleLiteralValue *) expr -> right_expression -> value;
                 IEEEdouble result =  IEEEdouble((u4) 0);
                 IEEEdouble::Fmodulus(left -> value, right -> value, result);

                 expr -> value = control.double_pool.FindOrInsert(result);
             }
             else if (expr -> Type() == control.float_type)
             {
                 FloatLiteralValue *left = (FloatLiteralValue *) expr -> left_expression -> value;
                 FloatLiteralValue *right = (FloatLiteralValue *) expr -> right_expression -> value;
                 IEEEfloat result = IEEEfloat(0);
                 IEEEfloat::Fmodulus(left -> value, right -> value, result);

                 expr -> value = control.float_pool.FindOrInsert(result);
             }
             else if (expr -> Type() == control.long_type)
             {
                 LongLiteralValue *left = (LongLiteralValue *) expr -> left_expression -> value;
                 LongLiteralValue *right = (LongLiteralValue *) expr -> right_expression -> value;

                 if (right -> value == 0)
                 {
                     ReportSemError(SemanticError::ZERO_DIVIDE,
                                    expr -> LeftToken(),
                                    expr -> RightToken());
                 }
                 else expr -> value = control.long_pool.FindOrInsert(left -> value % right -> value);
             }
             else if (expr -> Type() == control.int_type)
             {
                 IntLiteralValue *left = (IntLiteralValue *) expr -> left_expression -> value;
                 IntLiteralValue *right = (IntLiteralValue *) expr -> right_expression -> value;

                 if (right -> value == 0)
                 {
                     ReportSemError(SemanticError::ZERO_DIVIDE,
                                    expr -> LeftToken(),
                                    expr -> RightToken());
                 }
//
// There is a bug in the intel hardware where if one tries to compute ((2**32-1) / -1), he gets a ZeroDivide exception.
// Thus, instead of using the straightforward code below, we use the short-circuited one that follows:
//
//                 else expr -> value = control.int_pool.FindOrInsert(left -> value % right -> value);
//
                 else expr -> value = control.int_pool.FindOrInsert((left -> value  == (signed) 0x80000000 &&
                                                                     right -> value == (signed) 0xffffffff)
                                                                                     ? 0
                                                                                     : left -> value % right -> value);
             }
         }
    }

    return;
}


void Semantic::ProcessINSTANCEOF(AstBinaryExpression *expr)
{
    ProcessExpression(expr -> left_expression);
    ProcessExpression(expr -> right_expression);

    TypeSymbol *left_type  = expr -> left_expression -> Type(),
               *right_type = expr -> right_expression -> Type();

    if (left_type -> Primitive())
    {
        ReportSemError(SemanticError::TYPE_NOT_REFERENCE,
                       expr -> left_expression -> LeftToken(),
                       expr -> left_expression -> RightToken(),
                       expr -> left_expression -> Type() -> Name());
    }
    else if (! CanCastConvert(right_type, left_type, expr -> binary_operator_token)) // can left_type (source) be cast into right_type
    {
        ReportSemError(SemanticError::INVALID_INSTANCEOF_CONVERSION,
                       expr -> LeftToken(),
                       expr -> RightToken(),
                       left_type -> ContainingPackage() -> PackageName(),
                       left_type -> ExternalName(),
                       right_type -> ContainingPackage() -> PackageName(),
                       right_type -> ExternalName());
    }

    expr -> symbol = control.boolean_type;

    return;
}


void Semantic::ProcessBinaryExpression(Ast *expr)
{
    AstBinaryExpression *binary_expression = (AstBinaryExpression *) expr;
    (this ->* ProcessBinaryExpr[binary_expression -> binary_tag])(binary_expression);

    return;
}


void Semantic::ProcessTypeExpression(Ast *expr)
{
    AstTypeExpression *type_expression = (AstTypeExpression *) expr;

    AstArrayType *array_type = type_expression -> type -> ArrayTypeCast();
    Ast *actual_type = (array_type ? array_type -> type : type_expression -> type);

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

    if (array_type)
        type = type -> GetArrayType((Semantic *) this, array_type -> NumBrackets());

    type_expression -> symbol = type;

    return;
}


void Semantic::ProcessConditionalExpression(Ast *expr)
{
    AstConditionalExpression *conditional_expression = (AstConditionalExpression *) expr;

    ProcessExpression(conditional_expression -> test_expression);
    ProcessExpressionOrStringConstant(conditional_expression -> true_expression);
    ProcessExpressionOrStringConstant(conditional_expression -> false_expression);

    TypeSymbol *test_type  = conditional_expression -> test_expression -> Type();
    TypeSymbol *true_type  = conditional_expression -> true_expression -> Type();
    TypeSymbol *false_type = conditional_expression -> false_expression -> Type();

    if (test_type == control.no_type || true_type == control.no_type || false_type == control.no_type)
        conditional_expression -> symbol = control.no_type;
    else if (test_type != control.boolean_type)
    {
        ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
                       conditional_expression -> test_expression -> LeftToken(),
                       conditional_expression -> test_expression -> RightToken(),
                       conditional_expression -> test_expression -> Type() -> Name());
        conditional_expression -> symbol = control.no_type;
    }
    else if (true_type == control.void_type)
    {
        ReportSemError(SemanticError::TYPE_IS_VOID,
                       conditional_expression -> true_expression -> LeftToken(),
                       conditional_expression -> true_expression -> RightToken(),
                       conditional_expression -> true_expression -> Type() -> Name());
        conditional_expression -> symbol = control.no_type;
    }
    else if (false_type == control.void_type)
    {
        ReportSemError(SemanticError::TYPE_IS_VOID,
                       conditional_expression -> false_expression -> LeftToken(),
                       conditional_expression -> false_expression -> RightToken(),
                       conditional_expression -> false_expression -> Type() -> Name());
        conditional_expression -> symbol = control.no_type;
    }
    else if (true_type -> Primitive())
    {
        if (! false_type -> Primitive() ||
            (true_type != false_type && (true_type == control.boolean_type || false_type == control.boolean_type)))
        {
            ReportSemError(SemanticError::INCOMPATIBLE_TYPE_FOR_CONDITIONAL_EXPRESSION,
                           conditional_expression -> false_expression -> LeftToken(),
                           conditional_expression -> false_expression -> RightToken(),
                           conditional_expression -> false_expression -> Type() -> ContainingPackage() -> PackageName(),
                           conditional_expression -> false_expression -> Type() -> ExternalName(),
                           conditional_expression -> true_expression -> Type() -> ContainingPackage() -> PackageName(),
                           conditional_expression -> true_expression -> Type() -> ExternalName());
            conditional_expression -> symbol = control.no_type;
        }
        else // must be a numeric type
        {
            if (true_type == false_type)
                conditional_expression -> symbol = true_type;
            else // must be a numeric type
            {
                if (true_type == control.byte_type && false_type == control.short_type)
                {
                    conditional_expression -> true_expression =
                                ConvertToType(conditional_expression -> true_expression, control.short_type);
                    conditional_expression -> symbol = control.short_type;
                }
                else if (true_type == control.short_type && false_type == control.byte_type)
                {
                    conditional_expression -> false_expression =
                        ConvertToType(conditional_expression -> false_expression, control.short_type);
                    conditional_expression -> symbol = control.short_type;
                }
                else if (IsIntValueRepresentableInType(conditional_expression -> false_expression, true_type))
                {
                    conditional_expression -> false_expression =
                        ConvertToType(conditional_expression -> false_expression, true_type);
                    conditional_expression -> symbol = true_type;
                }
                else if (IsIntValueRepresentableInType(conditional_expression -> true_expression, false_type))
                {
                    conditional_expression -> true_expression =
                         ConvertToType(conditional_expression -> true_expression, false_type);
                    conditional_expression -> symbol = false_type;
                }
                else BinaryNumericPromotion(conditional_expression);
            }

            //
            // If all the relevant subexpressions are constants, compute the results and
            // set the value of the expression accordingly.
            //
            if (conditional_expression -> test_expression -> IsConstant())
            {
                IntLiteralValue *test = (IntLiteralValue *) conditional_expression -> test_expression -> value;

                if (test -> value && conditional_expression -> true_expression -> IsConstant())
                     conditional_expression -> value = conditional_expression -> true_expression -> value;
                else if ((! test -> value) && conditional_expression -> false_expression -> IsConstant())
                     conditional_expression -> value = conditional_expression -> false_expression -> value;
            }
        }
    }
    else
    {
        if (true_type == false_type)
            conditional_expression -> symbol = true_type;
        else if (false_type -> Primitive())
        {
            ReportSemError(SemanticError::INCOMPATIBLE_TYPE_FOR_CONDITIONAL_EXPRESSION,
                           conditional_expression -> false_expression -> LeftToken(),
                           conditional_expression -> false_expression -> RightToken(),
                           conditional_expression -> false_expression -> Type() -> ContainingPackage() -> PackageName(),
                           conditional_expression -> false_expression -> Type() -> ExternalName(),
                           conditional_expression -> true_expression -> Type() -> ContainingPackage() -> PackageName(),
                           conditional_expression -> true_expression -> Type() -> ExternalName());
            conditional_expression -> symbol = control.no_type;
        }
        else if (true_type == control.null_type)
            conditional_expression -> symbol = false_type;
        else if (false_type == control.null_type)
            conditional_expression -> symbol = true_type;
        else if (CanAssignmentConvert(false_type, conditional_expression -> true_expression))
        {
            conditional_expression -> true_expression = ConvertToType(conditional_expression -> true_expression, false_type);
            conditional_expression -> symbol = false_type;
        }
        else if (CanAssignmentConvert(true_type, conditional_expression -> false_expression))
        {
            conditional_expression -> false_expression = ConvertToType(conditional_expression -> false_expression, true_type);
            conditional_expression -> symbol = true_type;
        }
        else
        {
            ReportSemError(SemanticError::INCOMPATIBLE_TYPE_FOR_CONDITIONAL_EXPRESSION,
                           conditional_expression -> false_expression -> LeftToken(),
                           conditional_expression -> false_expression -> RightToken(),
                           conditional_expression -> false_expression -> Type() -> ContainingPackage() -> PackageName(),
                           conditional_expression -> false_expression -> Type() -> ExternalName(),
                           conditional_expression -> true_expression -> Type() -> ContainingPackage() -> PackageName(),
                           conditional_expression -> true_expression -> Type() -> ExternalName());
            conditional_expression -> symbol = control.no_type;
        }
    }

    return;
}


void Semantic::ProcessAssignmentExpression(Ast *expr)
{
    AstAssignmentExpression *assignment_expression = (AstAssignmentExpression *) expr;

    AstExpression *left_hand_side = assignment_expression -> left_hand_side;

    ProcessExpression(left_hand_side);
    ProcessExpressionOrStringConstant(assignment_expression -> expression);
    TypeSymbol *left_type = left_hand_side -> Type(),
               *right_type = assignment_expression -> expression -> Type();

    assignment_expression -> symbol = left_type;

    if (left_type == control.no_type || right_type == control.no_type)
        return;

    if (left_hand_side -> ArrayAccessCast())
    {
        //
        // This operation may throw ArrayStoreException
        //
        SymbolSet *exception_set = TryExceptionTableStack().Top();
        if (exception_set && (! left_type -> Primitive()))
        {
            exception_set -> AddElement(control.RuntimeException());
            exception_set -> AddElement(control.Error());
        }
    }
    else // the left-hand-side is a name
    {
        MethodSymbol *read_method = NULL;
        AstSimpleName *simple_name = left_hand_side -> SimpleNameCast();
        if (simple_name)
        {
            if (simple_name -> resolution_opt)
               read_method = simple_name -> resolution_opt -> symbol -> MethodCast();
        }
        else
        {
            AstFieldAccess *field_access = (AstFieldAccess *) left_hand_side;
            if (field_access -> resolution_opt)
                read_method = field_access -> resolution_opt -> symbol -> MethodCast();
        }

        if (read_method)
        {
            VariableSymbol *symbol = (VariableSymbol *) read_method -> accessed_member;
            assignment_expression -> write_method = TypeSymbol::GetWriteAccessMethod(symbol);
        }
    }

    if (assignment_expression -> assignment_tag == AstAssignmentExpression::EQUAL)
    {
        if (left_type != right_type)
        {
            if (CanAssignmentConvert(left_type, assignment_expression -> expression))
                assignment_expression -> expression = ConvertToType(assignment_expression -> expression, left_type);
            else if (assignment_expression -> expression -> IsConstant() &&
                     control.IsSimpleIntegerValueType(assignment_expression -> expression -> Type()))
            {
                if (left_type == control.byte_type)
                     ReportSemError(SemanticError::INVALID_BYTE_VALUE,
                                    assignment_expression -> expression -> LeftToken(),
                                    assignment_expression -> expression -> RightToken());
                else if (left_type == control.char_type)
                     ReportSemError(SemanticError::INVALID_CHARACTER_VALUE,
                                    assignment_expression -> expression -> LeftToken(),
                                    assignment_expression -> expression -> RightToken());
                else ReportSemError(SemanticError::INVALID_SHORT_VALUE,
                                    assignment_expression -> expression -> LeftToken(),
                                    assignment_expression -> expression -> RightToken());
            }
            else
            {
                ReportSemError(SemanticError::INCOMPATIBLE_TYPE_FOR_ASSIGNMENT,
                               assignment_expression -> LeftToken(),
                               assignment_expression -> RightToken(),
                               left_type -> ContainingPackage() -> PackageName(),
                               left_type -> ExternalName(),
                               right_type -> ContainingPackage() -> PackageName(),
                               right_type -> ExternalName());
            }
        }

        return;
    }

    //
    // In the current spec, it is stated that the type of both the left-hand
    // and right-hand side of an "op=" assignment must be primitive. However,
    // the left-hand side may be of type String if the operator is "+=" and
    // that case, the right-hand side may also be of type String (or anything
    // else).
    //
    // TODO: CONFIRM THAT THERE WAS A MISTAKE IN THE SPEC.
    //
    if (left_type == control.String() && assignment_expression -> assignment_tag == AstAssignmentExpression::PLUS_EQUAL)
    {
        if (right_type != control.String())
        {
            if (right_type == control.void_type)
                ReportSemError(SemanticError::VOID_TO_STRING,
                               assignment_expression -> expression -> LeftToken(),
                               assignment_expression -> expression -> RightToken());
            assignment_expression -> expression = ConvertToType(assignment_expression -> expression, control.String());
        }

        return;
    }

    if (! left_type -> Primitive())
    {
        ReportSemError(SemanticError::TYPE_NOT_PRIMITIVE,
                       left_hand_side -> LeftToken(),
                       left_hand_side -> RightToken(),
                       left_type -> Name());
        return;
    }

    if (! right_type -> Primitive())
    {
        ReportSemError(SemanticError::TYPE_NOT_PRIMITIVE,
                       assignment_expression -> expression -> LeftToken(),
                       assignment_expression -> expression -> RightToken(),
                       right_type -> Name());
        return;
    }

    switch(assignment_expression -> assignment_tag)
    {
        case AstAssignmentExpression::PLUS_EQUAL:
        case AstAssignmentExpression::STAR_EQUAL:
        case AstAssignmentExpression::SLASH_EQUAL:
        case AstAssignmentExpression::MOD_EQUAL:
        case AstAssignmentExpression::MINUS_EQUAL:
            BinaryNumericPromotion(assignment_expression);
            break;
        case AstAssignmentExpression::LEFT_SHIFT_EQUAL:
        case AstAssignmentExpression::RIGHT_SHIFT_EQUAL:
        case AstAssignmentExpression::UNSIGNED_RIGHT_SHIFT_EQUAL:
             if (! control.IsIntegral(left_type))
             {
                 ReportSemError(SemanticError::TYPE_NOT_INTEGRAL,
                                left_hand_side -> LeftToken(),
                                left_hand_side -> RightToken(),
                                left_type -> Name());
             }

             if (! control.IsIntegral(right_type))
             {
                 ReportSemError(SemanticError::TYPE_NOT_INTEGRAL,
                                assignment_expression -> expression -> LeftToken(),
                                assignment_expression -> expression -> RightToken(),
                                right_type -> Name());
             }

             assignment_expression -> left_hand_side = PromoteUnaryNumericExpression(left_hand_side);
             assignment_expression -> expression = PromoteUnaryNumericExpression(assignment_expression -> expression);
             if (assignment_expression -> expression -> Type() == control.long_type)
                 assignment_expression -> expression = ConvertToType(assignment_expression -> expression, control.int_type);
             break;
        case AstAssignmentExpression::AND_EQUAL:
        case AstAssignmentExpression::XOR_EQUAL:
        case AstAssignmentExpression::IOR_EQUAL:
             if (left_type != control.boolean_type || right_type != control.boolean_type) // if anyont of the exprs is not boolean
                 BinaryNumericPromotion(assignment_expression);
             break;
        default:
            assert(0);
            break;
    }

    return;
}