
//=============================================================================
/**
 *  @file    be_array.cpp
 *
 *  Extension of class AST_Array that provides additional means for C++
 *  mapping.
 *
 *  @author Copyright 1994-1995 by Sun Microsystems
 *  @author Inc. and Aniruddha Gokhale
 */
//=============================================================================

#include "be_array.h"
#include "be_codegen.h"
#include "be_scope.h"
#include "be_helper.h"
#include "be_visitor.h"
#include "utl_identifier.h"
#include "idl_defines.h"
#include "global_extern.h"

#include "ace/Log_Msg.h"

be_array::be_array (UTL_ScopedName *n,
                    unsigned long ndims,
                    UTL_ExprList *dims,
                    bool local,
                    bool abstract)
  : COMMON_Base (local,
                 abstract),
    AST_Decl (AST_Decl::NT_array,
              n,
              true),
    AST_Type (AST_Decl::NT_array,
              n),
    AST_ConcreteType (AST_Decl::NT_array,
                      n),
    AST_Array (n,
               ndims,
               dims,
               local,
               abstract),
    be_decl (AST_Decl::NT_array,
             n),
    be_type (AST_Decl::NT_array,
             n)
{
  if (!this->imported ())
    {
      idl_global->array_seen_ = true;
    }
}

int
be_array::create_name ()
{
  char namebuf [NAMEBUFSIZE];
  unsigned long i;
  UTL_ScopedName *n = nullptr;
  be_decl *scope = nullptr;

  ACE_OS::memset (namebuf,
                  '\0',
                  NAMEBUFSIZE);
  // Retrieve the base type.
  // The name always starts this way.
  be_type *bt = dynamic_cast<be_type*> (this->base_type ());

  if (!bt)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         "(%N:%l) be_array::"
                         "create_name - "
                         "bad base type\n"),
                        0);
    }

  ACE_OS::sprintf (namebuf,
                   "_tao_array_%s",
                   bt->local_name ()->get_string ());

  // Now append dimensions.
  for (i = 0; i < this->n_dims (); ++i)
    {
      AST_Expression *expr = this->dims ()[i];

      // Dimension value.
      if ((expr == nullptr) || ((expr != nullptr) && (expr->ev () == nullptr)))
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             "(%N:%l) be_array::"
                             "create_name - "
                             "bad array dimension\n"),
                            -1);
        }
      if (expr->ev ()->et == AST_Expression::EV_ulong)
        {
          ACE_OS::sprintf (namebuf,
                           "%s_%d",
                           namebuf,
                           ((int)expr->ev ()->u.ulval));
        }
      else
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             "(%N:%l) be_array::"
                             "create_name - "
                             "bad dimension value\n"),
                            -1);
        }
    }

  // Now see if we have a fully scoped name and if so, generate one.
  scope = dynamic_cast<be_scope*> (this->defined_in ())->decl ();

  if (scope)
    {
      // Make a copy of the enclosing scope's  name.
      n = (UTL_ScopedName *)scope->name ()->copy ();

      Identifier *id = nullptr;
      ACE_NEW_RETURN (id,
                      Identifier (ACE_OS::strdup (namebuf)),
                      -1);

      UTL_ScopedName *sn = nullptr;
      ACE_NEW_RETURN (sn,
                      UTL_ScopedName (id,
                                      nullptr),
                      -1);

      // Add our local name as the last component.
      n->nconc (sn);
      // Set the fully scoped name.
      this->set_name (n);
    }
  else
    {
      // We better be not here because we must be inside some scope,
      // at least the ROOT scope.
      return -1;
    }

  return 0;
}

// Overriden method.
void
be_array::compute_tc_name ()
{
  // Array TypeCodes can only be accessed through an alias
  // TypeCode.  Generate a TypeCode name that is meant for internal
  // use alone.

  Identifier * tao_id = nullptr;
  ACE_NEW (tao_id,
           Identifier ("TAO"));

  ACE_NEW (this->tc_name_,
           UTL_ScopedName (tao_id,
                           nullptr));

  ACE_CString local_tc_name =
    ACE_CString ("tc_")
    + ACE_CString (this->flat_name ());

  Identifier * typecode_scope = nullptr;
  ACE_NEW (typecode_scope,
           Identifier ("TypeCode"));

  UTL_ScopedName * tc_scope_conc_name = nullptr;
  ACE_NEW (tc_scope_conc_name,
           UTL_ScopedName (typecode_scope,
                           nullptr));

  this->tc_name_->nconc (tc_scope_conc_name);

  Identifier * id = nullptr;
  ACE_NEW (id,
           Identifier (local_tc_name.c_str ()));

  UTL_ScopedName * conc_name = nullptr;
  ACE_NEW (conc_name,
           UTL_ScopedName (id,
                           nullptr));

  this->tc_name_->nconc (conc_name);
}

// Code generation.

int
be_array::gen_dimensions (TAO_OutStream *os,
                          unsigned short slice)
{
   // Loop index.
   unsigned long i;

  // Print our dimensions.
  for (i = (slice ? 1 : 0); i < this->n_dims (); ++i)
    {
      // Retrieve the ith.
      AST_Expression *expr = this->dims ()[i];

      // Dimension value.
      if ((expr == nullptr) || ((expr != nullptr) && (expr->ev () == nullptr)))
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             "(%N:%l) be_array::"
                             "gen_dimensions - "
                             "bad array dimension\n"),
                            -1);
        }

      if (expr->ev ()->et == AST_Expression::EV_ulong)
        {
          *os << "[" << ((int)expr->ev ()->u.ulval) << "]";
        }
      else
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             "(%N:%l) be_array::"
                             "gen_dimensions - "
                             "bad dimension value\n"),
                            -1);
        }
    }

  return 0;
}

// Overridden method
void
be_array::gen_ostream_operator (TAO_OutStream *os,
                                bool use_underscore)
{
  be_scope* scope = dynamic_cast<be_scope*> (this->defined_in ());
  be_decl* parent = scope->decl ();
  ACE_CString arg_name (ACE_CString (parent->full_name ())
                        + "::"
                        + (use_underscore ? "_" : "")
                        + this->local_name ()->get_string ()
                        + "_forany &_tao_array");

  // Using 'const' with xxx_forany here prevents the compiler from
  // automatically converting back to xxx_slice *.
  *os << be_nl
      << "std::ostream& operator<< (" << be_idt << be_idt_nl
      << "std::ostream &strm," << be_nl
      << "const " << arg_name.c_str () << be_uidt_nl
      << ")" << be_uidt_nl
      << "{" << be_idt_nl
      << "strm << \"" << this->name () << "\";" <<  be_nl_2;

  ACE_CDR::ULong ndims = this->n_dims ();
  ACE_CDR::ULong i = 0;

  for (i = 0; i < ndims; ++i)
    {
      *os << "strm << \"[\";" << be_nl_2;

      AST_Expression *expr = this->dims ()[i];

      // Generate a loop for each dimension.
      *os << "for (::CORBA::ULong i" << i << " = 0; i" << i << " < "
          << expr->ev ()->u.ulval << "; ++i" << i << ")" << be_idt_nl
          << "{" << be_idt_nl
          << "if (i" << i << " != 0)" << be_idt_nl
          << "{" << be_idt_nl
          << "strm << \", \";" << be_uidt_nl
          << "}" << be_uidt_nl << be_nl;
    }

  *os << "strm << ";

  ACE_CString instance_name ("_tao_array.in ()");

  for (i = 0; i < ndims; ++i)
    {
      char *working = instance_name.rep ();
      instance_name += "[i";
      instance_name += ACE_OS::itoa (i, working, 10);
      instance_name += "]";
    }

  be_type *bt = dynamic_cast<be_type*> (this->base_type ());
  bt->gen_member_ostream_operator (os,
                                   instance_name.c_str (),
                                   use_underscore,
                                   false);

  *os << ";";

  for (i = 0; i < ndims; ++i)
    {
      *os << be_uidt_nl
          << "}" << be_uidt_nl << be_nl
          << "strm << \"]\";";
    }

  *os << be_nl
      << "return strm;" << be_uidt_nl
      << "}" << be_nl;
}

void
be_array::gen_member_ostream_operator (TAO_OutStream *os,
                                       const char *instance_name,
                                       bool use_underscore,
                                       bool accessor)
{
  be_scope* scope = dynamic_cast<be_scope*> (this->defined_in ());
  be_decl* parent = scope->decl ();
  ACE_CString decl_name (ACE_CString (parent->full_name ())
                         + "::"
                         + (use_underscore ? "_" : "")
                         + this->local_name ()->get_string ());

 // The container is always const, so the member is const as well,
 // but we have to cast it away for the forany constructor.
 *os << decl_name.c_str () << "_forany ("
     << "const_cast< " << decl_name.c_str () << "_slice *> (";

  this->be_type::gen_member_ostream_operator (os,
                                              instance_name,
                                              use_underscore,
                                              accessor);

  *os << "))";
}

int
be_array::accept (be_visitor *visitor)
{
  return visitor->visit_array (this);
}

void
be_array::destroy ()
{
  this->be_type::destroy ();
  this->AST_Array::destroy ();
}
