2005/5/9

     
 

DmiProxyGeneratorExt.cpp

artefaktur

// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
#include "DmiProxyGeneratorExt.h"
//#include "TypeScope.h"
#include <acdk/lang/System.h>
#include <acdk/lang/Void.h>
#include <acdk/io/PrintWriter.h>
#include <acdk/lang/dmi/ClazzAttributesRes.h>
#include <acdk/util/logging/Log.h>

namespace acdk {
namespace tools {
namespace mc {

using namespace acdk::lang::dmi;


typedef DmiProxyGeneratorExt::ClazzMethodInfoArray ClazzMethodInfoArray;

bool hasMethod( ClazzMethodInfoArray& methods, const ClazzMethodInfo* mi)
{
  for (ClazzMethodInfoArray::iterator it = methods.begin(); it < methods.end(); ++it)
  {
    if (mi->equals(*it, CompareName | CompareArgs) == true)
      return true;
  }
  return false;
}

void
ClazzInfo_getVirtualMethods(const ClazzInfo* ci, DmiProxyGeneratorExt::ClazzMethodInfoArray& methods)
{
  int i;
  
  for (i = 0; i < ci->getMethodsCount(); ++i)
  {
    const ClazzMethodInfo* mi = ci->methods[i];
    if (mi->flags & MiMiVirtual && mi->flags & MiMiOrgPoly && (mi->flags & MiNoDmiProxy) == 0)
    {
      if (hasMethod(methods, mi) == false)
        methods.push_back(mi);
    }
  }
  for (i = 0; i < ci->getInterfacesCount(); ++i)
  {
    if (ci->interfaces[i]->type == 0)
    {
      ACDK_LOG(Warn, SBSTR("An interface of " <<  ci->name << " is not defined"));      
    }
    else
      ClazzInfo_getVirtualMethods(ci->interfaces[i]->type, methods);
  }
}

bool
ClazzInfo_findConstructors(const ClazzInfo* ci, ClazzMethodInfoArray& methods)
{
  int i;
  bool hasPrivate = false;
  for (i = 0; i < ci->getMethodsCount(); ++i)
  {
    const ClazzMethodInfo* mi = ci->methods[i];
    if (mi->flags & MiMiConstructor)
    {
      if (mi->flags & MiPrivate)
        hasPrivate = true;
      else //if (mi->flags & MiMiOrgPoly)
        methods.push_back(mi);
    }
  }
  return methods.size() > 0 || hasPrivate == false;
}

void 
DmiProxyGeneratorExt::generateProxyMethodArgDecl(const acdk::lang::dmi::ClazzMethodInfo* mi, StringBuffer& sb)
{
  for (int i = 0; i < mi->getArgumentCount(); ++i)
  {
    if (i > 0)
      sb << ", ";
    mi->methodArgs[i]->toTypeString(sb, TpFtFormatStandard);
  }
}
void 
DmiProxyGeneratorExt::generateProxyMethodThrowDecl(const acdk::lang::dmi::ClazzMethodInfo* mi, StringBuffer& sb)
{
  int count = mi->getExceptionsCount();
  if (count == 0)
    return ;
  sb << " THROWS" << count << "(";
  for (int i = 0;  i < count; ++i)
  {
    if (i > 0)
      sb << ", ";
    mi->exceptions[i]->toTypeString(sb, TpFtFormatStandard);
  }
  sb << ")";
}

RString getArgEnumCaster(const ClazzMethodArgInfo* ai)
{
  ClazzAttributeResValue attr = ClazzAttributesRes::getAttribute((MetaInfo*)ai, "__enumArgInfo");
  const ClazzEnumInfo* ei = (const ClazzEnumInfo*)attr.data; 
  if (ei != 0 && ei->name != 0)
    return "(" + ei->toTypeString(TpFtAcdkType | TpFtFqName) + ")";
  return "";
}

void 
DmiProxyGeneratorExt::generateProxyMethodArgCall(const acdk::lang::dmi::ClazzMethodInfo* mi, StringBuffer& sb)
{
  for (int i = 0; i < mi->getArgumentCount(); ++i)
  {
    if (i > 0)
      sb << ", ";

   if (mi->methodArgs[i]->type->isIntClazz() == true &&  
      ClazzAttributesRes::hasAttribute((MetaInfo*)mi->methodArgs[i], "__enumArgInfo"))
   {
    sb << getArgEnumCaster(mi->methodArgs[i]);
   }
    sb << (char*)mi->methodArgs[i]->name;
  }
}

void 
DmiProxyGeneratorExt::generateProxyClassDeclDefConstructor(const acdk::lang::dmi::ClazzMethodInfo* mi, StringBuffer& sb)
{
  RString name = mi->name;
  sb
    << "  " << name << "_DmiProxy("
    ;
  generateProxyMethodArgDecl(mi, sb);
  sb << ")";
  generateProxyMethodThrowDecl(mi, sb);
  sb << "\n  : " << name << "(";
  generateProxyMethodArgCall(mi, sb);
  sb 
    << 
    ")\n"
    "  {\n"
    "     clazzInfo()->_resolveSupers(true, false);\n"
    "     ACDK_FQ_SUPER_QUALIFIER(::acdk::lang::dmi::, DmiProxyBase)::_initThis(this);\n"
    "  }\n"
    ;
}

int getMethodIndex(const ClazzInfo* ci, const ClazzMethodInfo* mi)
{
  for (int i = 0; i < ci->getMethodsCount(); ++i)
    if (ci->methods[i] == mi)
      return i;
  return -1;
}

bool
hasEnumReturn(const ClazzMethodInfo* mi)
{
  return ClazzAttributesRes::hasAttribute((MetaInfo*)mi, "__enumArgInfo");

  
}
RString getReturnType(const ClazzMethodInfo* mi)
{
  if (hasEnumReturn(mi) == false)
  {
    StringBuffer sb;
    mi->returnType->toTypeString(sb, TpFtFormatStandard);
    return sb.toString();
  }
  ClazzAttributeResValue attr = ClazzAttributesRes::getAttribute((MetaInfo*)mi, "__enumArgInfo");
  
  const ClazzEnumInfo* ei = (const ClazzEnumInfo*)attr.data; 
  if (ei == 0)
  {
    ACDK_LOG(Error, SBSTR("Return enum type of method " <<  mi->name << " is not defined"));
    return "int";
  }
  return ei->toTypeString(TpFtAcdkType | TpFtFqName);
}

bool checkValidMethod(const acdk::lang::dmi::ClazzMethodInfo* mi)
{
  if (mi->returnType == 0)
  {
    ACDK_LOG(Warn, SBSTR("Return type of method " <<  mi->name << " is not defined"));
    return false;
  }
  int argcount = mi->getArgumentCount();
  for (int i = 0; i < argcount; ++i)
  {
    const ClazzMethodArgInfo* ai = mi->methodArgs[i];
    if (ai->type == 0)
    {
      ACDK_LOG(Warn, SBSTR("Argument type of argument " << ai->name  << " of method " <<  mi->name << " is not defined"));
      return false;
    }
  }
  return true;
}

void 
DmiProxyGeneratorExt::generateProxyClassMethod(const acdk::lang::dmi::ClazzInfo* super, const acdk::lang::dmi::ClazzMethodInfo* mi, StringBuffer& sb)
{
  if (checkValidMethod(mi) == false)
    return;
  const ClazzInfo* ci = (const ClazzInfo*)mi->_scopeParent;
  RString name = mi->name;
  RString cname = ci->name;
  RString supername = super->name;
  sb 
    << "  ";
  // mi->returnType->toTypeString(sb, TpFtFormatStandard);
  sb << getReturnType(mi);
  sb << " " << name << "(";
  generateProxyMethodArgDecl(mi, sb);
  sb << ")";
  generateProxyMethodThrowDecl(mi, sb);
  int argcount = mi->getArgumentCount();
  int i;
  
  sb 
    << "\n  {\n"
    ;
  if ((mi->flags & MiPrivate) == 0 && (mi->flags & MiMiAbstract) == 0)
  {
    int methodidx = getMethodIndex(ci, mi);
    sb << "    if (_dmiProxyIsOverloaded(getClazzInfo(), ";
    
    const acdk::lang::dmi::ClazzInfo* methodclazz = reinterpret_cast<const acdk::lang::dmi::ClazzInfo*>(mi->_scopeParent);
    
    RString methodSuper = SBSTR("ACDK_FQ_SUPER_QUALIFIER(::" << RString(methodclazz->ns)->replace("/", "::") << "::, " << methodclazz->name << ")");
    RString methodBase =  SBSTR("ACDK_FQ_SUPER_QUALIFIER(::" << RString(super->ns)->replace("/", "::") << "::, " << super->name << ")");
    
    //acdk::lang::System::out->println("method: " + supername + "::" + name + "; methodSuper: " + methodSuper + "; " + methodBase);
    
    sb << methodSuper << "::clazzInfo()->methods[" << methodidx << "]) == false)\n    {\n"
       << "      ";
    if ((void*)mi->returnType != (void*)Void::getTYPE()->objectClazzInfo())
      sb << "return ";
    sb << methodBase << "::" << name << "(";

    for (i = 0; i < argcount; ++i)
    {
      const ClazzMethodArgInfo* ai = mi->methodArgs[i];
      if (i > 0)
        sb << ", ";
      sb << (RString)ai->name;
    }
    sb << ");\n";
    if ((void*)mi->returnType == (void*)Void::getTYPE()->objectClazzInfo())
      sb << "      return;\n";
    sb << "    }\n";
  }
  sb 
    << "    ::acdk::lang::dmi::ScriptVar __acdk_retval;\n"
    << "    ::acdk::lang::dmi::ScriptVarArray __acdk_args(" << argcount << ");\n"
   ;
  
  for (i = 0; i < argcount; ++i)
  {
    const ClazzMethodArgInfo* ai = mi->methodArgs[i];
    RString argname = ai->name;
    sb << RString("    __acdk_args[") << i << "] = ";
    if (ai->flags & MiAiOut && ai->flags & MiAiIn)
      sb << "::acdk::lang::inoutOf(" << argname << ");\n";
    else if (ai->flags & MiAiOut)
      sb << "::acdk::lang::outOf(" << argname << ");\n";
    else
      sb << "::acdk::lang::inOf(" << argname << ");\n";
  }
  sb << "    _dmiProxyGetTarget()->standardDispatch(\"" << name
     << "\", __acdk_retval, __acdk_args, _dmiClient, Nil, 0, _dmiProxyGetTarget()->clazzInfo(), ";
  /*
    sb << "&" << mi->_classInfo->name << "_method_" << mi->getJavaSignature(true, mi->args->size());
  else
  */
  sb << "0);\n";

  if (mi->returnType->isVoidClazz() == false) 
  {
    sb << "    return ";
    if (mi->returnType->getMetaInfo()->isEnumInfo() == true || hasEnumReturn(mi) == true)
    {
      sb << "(" << getReturnType(mi) << ")(int)";
    }      
    else if (mi->returnType->isBasicClazz() == false) 
    {
      sb << "(";
      mi->returnType->toTypeString(sb, TpFtFormatStandard);
      sb << ")(::acdk::lang::RObject)";
    }
    sb << "__acdk_retval;\n";
  }
  sb << "  }\n";
  
}

RString getScriptVarAccessor(const ClazzMethodArgInfo* ai)
{
 if (ai->type->isBoolClazz() == true)
 {
   if (ai->flags & MiAiOut)
     return "getBoolRef()"; 
   else
    return "getBoolVar()";
  }
  if (ai->type->isCharClazz() == true)
  {
   if (ai->flags & MiAiOut)
     return "getCharRef()"; 
   else
    return "getCharVar()";
  }
  if (ai->type->isUcCharClazz() == true)
  {
   if (ai->flags & MiAiOut)
     return "getUcCharRef()"; 
   else
    return "getUcCharVar()";
  }
  if (ai->type->isByteClazz() == true)
  {
   if (ai->flags & MiAiOut)
     return "getByteRef()"; 
   else
    return "getByteVar()";
  }
  if (ai->type->isShortClazz()  == true)
  {
   if (ai->flags & MiAiOut)
     return "getShortRef()"; 
   else
    return "getShortVar()";
  }
  if (ai->type->isIntClazz() == true)
  {
   if (ai->flags & MiAiOut)
     return "getIntRef()"; 
   else
    return "getIntVar()";
  }
  if (ai->type->isLongClazz()  == true)
  {
   if (ai->flags & MiAiOut)
     return "getLongRef()"; 
   else
    return "getLongVar()";
  }
  if (ai->type->isFloatClazz()  == true)
  {
   if (ai->flags & MiAiOut)
     return "getFloatRef()"; 
   else
    return "getFloatVar()";
  }
  if (ai->type->isDoubleClazz()  == true)
  {
   if (ai->flags & MiAiOut)
     return "getDoubleRef()"; 
   else
    return "getDoubleVar()";
  }
  else 
  {
    if (ai->flags & MiAiOut)
     return "getObjectRef()"; 
   else
    return "getObjectVar()";
  }
}



RString getScriptVarCaster(const ClazzMethodArgInfo* ai)
{
  if (ai->type->isBasicClazz() == true)
  {
    if (ai->type->isIntClazz() == true &&  
      ClazzAttributesRes::hasAttribute((MetaInfo*)ai, "__enumArgInfo"))
    {
      return getArgEnumCaster(ai);
    }
    return "";
  }
  StringBuffer sb;
  sb << "(";
  ai->type->toTypeString(sb, TpFtAcdkType | TpFtRHPrefix | TpFtFqName);
  if (ai->flags & MiAiOut)
    sb << "&";
  sb << ")";
  return sb.toString();
}

void 
DmiProxyGeneratorExt::generateDispatchMethod(const acdk::lang::dmi::ClazzMethodInfo* mi, StringBuffer& sb)
{
  RString methodsig = mi->toTypeString(0, TpFtACDKSignature);
  RString fname = mi->name;
  sb 
    << "  static const ::acdk::lang::dmi::ClazzMethodInfo*\n"
    << "  " << methodsig << "_dispatch(::acdk::lang::Object* This_, IN(::acdk::lang::RString) fname, ::acdk::lang::dmi::ScriptVar& ret, ::acdk::lang::dmi::ScriptVarArray& args, ::acdk::lang::dmi::DmiClient& dc, IN(::acdk::lang::RStringArray) namedArgs, int flags, const ::acdk::lang::dmi::ClazzInfo* clazzinfo, const ::acdk::lang::dmi::ClazzMethodInfo* methinf)\n"
    << "  {\n"
    << "    "
    ;
  if (mi->returnType->isVoidClazz() == false)
  {
    sb << "ret = ";
    if (mi->flags & MiMiConstructor)
    {
      sb << "(::acdk::lang::RObject) new " << fname << "_DmiProxy";
    }
  }
  else
  {
    // ### TODO implement
  }
  sb << "(";
  int i;
  int argcount = mi->getArgumentCount();
  for (i = 0; i < argcount; ++i)
  {
    const ClazzMethodArgInfo* ai = mi->methodArgs[i];
    if (i > 0)
      sb << ", ";
    sb << getScriptVarCaster(ai) << "args[" << i << "]." << getScriptVarAccessor(ai);
  }
  sb 
    << ");\n"
    << "    return methinf;\n"
    << "  }\n";
}

bool hasProtectedDefaultConstructor(const acdk::lang::dmi::ClazzInfo* ci)
{
  for (int i = 0; i < ci->getMethodsCount(); ++i)
  {
    const acdk::lang::dmi::ClazzMethodInfo* mi = ci->methods[i];
    if ((mi->flags & MiMiConstructor) && (mi->flags & MiProtected) && mi->getArgumentCount() == 0)
      return true;
  }
  return false;
}

void 
DmiProxyGeneratorExt::generateProxyClassDecl(const acdk::lang::dmi::ClazzInfo* ci, 
                                             StringBuffer& sb,
                                             ClazzMethodInfoArray& constr, ClazzMethodInfoArray& methods)
{
  RString clsname = ci->name;
  sb 
    << "class " << clsname << "_DmiProxy\n"
    ;
  if (ci->flags & MiCiInterface)
    sb 
      << ": extends ::acdk::lang::Object\n"
      << ", implements " << clsname << "\n";
  else
    sb
      << ": extends " << clsname << "\n";
  sb
    << ", implements ::acdk::lang::dmi::DmiProxyBase\n"
    << "{\n"
    << "  ACDK_PROXY_WITH_METAINFO(" << clsname << ")\n"
    << "public:\n"
  ;
  sb << "  ::acdk::lang::Object* _cast(const ::acdk::lang::dmi::ClazzInfo* ci)\n"
        "  {\n"
        "    ::acdk::lang::Object* ret = _dmiProxyCast(ci);\n"
        "    if (ret != 0)\n"
        "      return ret;\n"
        "    ret =  " << clsname << "::_cast(ci);\n"
        "    return ret;\n"
      "  }\n"
      "  virtual void getCollectableFields(FieldReferences& fields)\n"
      "  {\n"
      "    ACDK_FQ_SUPER_QUALIFIER(" << RString(ci->ns)->replace("/", "::") << "::, " << ci->name  << ")::getCollectableFields(fields);\n"
      "    fields.push_back((::acdk::lang::RObject*)_dmiTarget._ref_this());\n"
      "  }\n"
      ;
  if ((ci->flags & MiCiInterface) == MiCiInterface || hasProtectedDefaultConstructor(ci) == true)
  {
    sb << "  static ::acdk::lang::RObject create_instance() { return new " << clsname << "_DmiProxy(); }\n";
  } 
  sb << "  virtual bool _gc_releaseRef(bool force = false) const { return ACDK_FQ_SUPER_QUALIFIER(::acdk::lang::dmi::, DmiProxyBase)::_gc_releaseRef(this); }\n";
  sb << "  ::acdk::lang::Object* getDmiTarget(bool& forwarded, const ::acdk::lang::dmi::ClazzInfo*& ci) { return _dmiProxygetDmiTarget(forwarded, ci); }\n";
  int i;
  if (constr.size() == 0)
  {
    ACDK_NLOG("acdk.tools.mc", Error, SBSTR("Class " <<  ci->name << " has not defined a constructor. A constructor is needed for generating a DmiProxy"));
  }
  for (i = 0; i < constr.size(); ++i)
  {
    generateProxyClassDeclDefConstructor(constr[i], sb);
  }
  for (i = 0; i < methods.size(); ++i)
  {
    generateProxyClassMethod(ci, methods[i], sb);
  }
  for (i = 0; i < constr.size(); ++i)
  {
    generateDispatchMethod(constr[i], sb);
  }
  sb << "};\n\n";
}

RString clazzInfoExpr(const ClazzInfo* ci)
{
  if (ci->isBoolClazz() == true)
    return "::acdk::lang::dmi::ClazzInfo::getBoolClazz()";
  if (ci->isCharClazz() == true)
    return "::acdk::lang::dmi::ClazzInfo::getCharClazz()";
  if (ci->isUcCharClazz() == true)
    return "::acdk::lang::dmi::ClazzInfo::getUcCharClazz()";
  if (ci->isByteClazz() == true)
    return "::acdk::lang::dmi::ClazzInfo::getByteClazz()";
  if (ci->isShortClazz()  == true)
    return "::acdk::lang::dmi::ClazzInfo::getShortClazz()";
  if (ci->isIntClazz() == true)
    return "::acdk::lang::dmi::ClazzInfo::getIntClazz()";
  if (ci->isLongClazz()  == true)
    return "::acdk::lang::dmi::ClazzInfo::getLongClazz()";
  if (ci->isFloatClazz()  == true)
    return "::acdk::lang::dmi::ClazzInfo::getFloatClazz()";
  if (ci->isDoubleClazz()  == true)
    return "::acdk::lang::dmi::ClazzInfo::getDoubleClazz()";
  if (ci->isVoidClazz() == true)
    return "::acdk::lang::dmi::ClazzInfo::getVoidClazz()";
  return ci->toTypeString(TpFtAcdkType | TpFtFqName) + "::clazzInfo()";
}

void 
DmiProxyGeneratorExt::generateProxyCiMethod(const acdk::lang::dmi::ClazzMethodInfo* mi, StringBuffer& sb)
{
  RString fname = mi->name;
  if (mi->flags & MiMiConstructor)
    fname = fname + "_DmiProxy";

  RString cname = mi->_scopeParent->name;
  int argcount = mi->getArgumentCount();
  RString methodsig = mi->toTypeString(0, TpFtACDKSignature);
  int i;
  for (i = 0; i < argcount; ++i)
  {
    const ClazzMethodArgInfo* ai = mi->methodArgs[i];
    RString argname = ai->name;
    RString argns = ai->ns;
    
    sb 
      << "::acdk::lang::dmi::ClazzMethodArgInfo " << cname << "_DmiProxy_methods_" << methodsig
      << "_arg_" << argname << " =\n{\n"
      << "  " << MetaInfo::flagsToString(ai->flags, MethodArgInfoExtFlags(0), TpFtFqName | TpFtAcdkType) << ",\n"
      << "  0, //AttributesRes\n"
      << "  \"" << argname << "\",\n"
      << "  -1, // hashCode\n"
      << "  \"" << argns << "\", // ns\n"
      << "  0, // _scopeParent\n"
      << "  0, // _nextSibling\n"
      << "  "
      ;
    
    ;
    sb << clazzInfoExpr(ai->type)  << "\n"
      << "};\n\n"
      ;
  }

  sb << "::acdk::lang::dmi::ClazzMethodArgInfo* " << cname << "_methods_" << methodsig << "_args[] = \n{\n";
  for (i = 0; i < argcount; ++i)
  {
    const ClazzMethodArgInfo* ai = mi->methodArgs[i];
    RString argname = ai->name;
    sb << "  &" << cname << "_DmiProxy_methods_" << methodsig
      << "_arg_" << argname << ",\n";
  }
  sb 
    << "  0\n};\n\n";
  
  

  sb 
    << "::acdk::lang::dmi::ClazzMethodInfo " << cname << "_DmiProxy_methods_" << methodsig << " = \n{\n"
    << "  " << MetaInfo::flagsToString(mi->flags, MethodInfoExtFlags(0), TpFtFqName | TpFtAcdkType) << ",\n"
    << "  0, //AttributesRes\n" 
    << "  \"" << fname << "\",\n"
    << "  -1, // hashCode\n"

    << "  \"\", // ns\n"
    << "  0, // _scopeParent\n" 
    << "  0, // _nextScopeSibling\n" 
    << "  " << cname << "::clazzInfo(), // returnType\n"
    << "  \"" << (RString)mi->altlabel << "_DmiProxy\", // altname\n"
    << "  -1, // altnamehashCode\n"
    << "  " << cname << "_methods_" << methodsig << "_args,\n"
    << "  0, // argumentCount\n"
    << "  0, // excpetions,\n" // ### TODO
    << "  " << cname << "_DmiProxy::" << methodsig << "_dispatch,\n" // ### TODO
    << "  ::acdk::lang::dmi::ClazzMethodInfo::DefaultDispatchThrowableFunc, \n" // ### TODO
    << "  0 // cached methodhash\n"
    << "};\n\n"
    ;

}

void 
DmiProxyGeneratorExt::generateProxyCiInterfaces(const acdk::lang::dmi::ClazzInfo* ci, StringBuffer& sb)
{
  RString cname = ci->name;

  sb 
    << "::acdk::lang::dmi::ClazzSuperInfo " << cname << "_DmiProxy_super" << " =\n{\n"
    << "  ::acdk::lang::dmi::MiPublic,\n"
    << "  0, //AttributesRes\n"
    << "  " << cname << "::clazzInfo()\n};\n\n"
    ;

  sb 
    << "::acdk::lang::dmi::ClazzSuperInfo* _" << cname << "_DmiProxy_interfaces[] =\n{\n"
    << "  &" << cname << "_DmiProxy_super,\n"
    << "  0\n};\n\n"
    ;
}

void 
DmiProxyGeneratorExt::generateProxyCiMethods(const acdk::lang::dmi::ClazzInfo* ci, ClazzMethodInfoArray& methods, StringBuffer& sb)
{
  RString cname = ci->name;
  int i;
  for (i = 0; i < methods.size(); ++i)
    generateProxyCiMethod(methods[i], sb);

  sb << "::acdk::lang::dmi::ClazzMethodInfo* " << cname << "_methods[] = \n{\n";
  for (i = 0; i < methods.size(); ++i)
  {
    const acdk::lang::dmi::ClazzMethodInfo* mi = methods[i];
    RString methodsig = mi->toTypeString(0, TpFtACDKSignature);
    sb << "  &" << cname << "_DmiProxy_methods_" << methodsig << ",\n";
  }
  sb << "  0\n};\n\n";
}

void
createStandardConstructor(const acdk::lang::dmi::ClazzInfo* ci, ClazzMethodInfoArray& constructors)
{
  static acdk::lang::dmi::ClazzMethodInfo mi;
  memset(&mi, 0, sizeof(mi));
  mi.flags = MiMiConstructor | MiMethodInfo;
  mi.name = ci->name;
  mi._scopeParent = (const NamedScopedMetaInfo*)ci;
  /*
  const char* ns;
  mutable const NamedScopedMetaInfo* _scopeParent;
  mutable const NamedScopedMetaInfo* _nextScopeSibling;
  */
  mi.returnType = ci;
  /*
  const char* altlabel;
  ClazzMethodArgInfo** methodArgs;
  ClazzInfo** exceptions;
  */
  constructors.push_back(&mi);
}

void 
DmiProxyGeneratorExt::generateProxy(const acdk::lang::dmi::ClazzInfo* ci, StringBuffer& sb)
{
  ci = ci->loadFullClazzInfo(false, true);
  if (ci->flags & MiNoDmiProxy)
    return;
  ClazzMethodInfoArray constructors;
  if (ClazzInfo_findConstructors(ci, constructors) == false)
    return;

  if (constructors.size() == 0)
  {
    createStandardConstructor(ci, constructors);
  }
  ClazzMethodInfoArray virtualmethods;
  ClazzInfo_getVirtualMethods(ci, virtualmethods);
  if (virtualmethods.size() == 0)
    return;

  generateProxyClassDecl(ci, sb, constructors, virtualmethods);
  
  generateProxyCiInterfaces(ci, sb);
  generateProxyCiMethods(ci, constructors, sb);
  

  RString clsname = ci->name;
  RString nsname = ci->ns;
  

  sb << "::acdk::lang::dmi::ClazzInfo* " << clsname << "_DmiProxy::clazzInfo()\n"
     << "{\n"
     << "static ::acdk::lang::dmi::ClazzInfo _clazzInfo =\n"
     << "  {\n"
     << "    ::acdk::lang::dmi::MiClazzInfo | ::acdk::lang::dmi::MiResolved, // clazz-flags\n"
     << "    0, //AttributesRes\n"
     << "    \"" << clsname << "_DmiProxy\", // name of class\n"
     << "  -1, // hashCode\n"
     << "    \"" << nsname << "\", // the namespace\n"
     << "     0, // _scopeParent\n"
     << "     0, // _nextSibling\n"
     << "     0, // type\n"
     << "     0, // _firstChild\n"
     << "     _" << clsname << "_DmiProxy_interfaces, // pointer to Array of ClazzInfo references\n"
     << "     0, // count of Super / Interfaces\n"
     << "     0, // pointer to Array of fields\n"
     << "     0, // count of Fields\n"
     << "     " << clsname << "_methods, // pointer to Array of Methods\n"
     << "     0, // count of Methods\n"
     ;
  if ((ci->flags & MiCiInterface) == MiCiInterface || hasProtectedDefaultConstructor(ci) == true)
    sb << "     " << clsname << "_DmiProxy::create_instance, // create-function for cloning/serializing\n";
  else
    sb << "     0, // create-function for cloning/serializing\n";

  sb
     << "     0, // create-function for cloning/serializing arrays\n"
     << "     0, // create-function for cloning/serializing arrays\n"
     << "     0, // Class* thisClass; chaching instance\n"
     << "     0, // jlong serialVersionUID; for serialization\n"
     << "     ::acdk::lang::dmi::StdDispatch::_invoke_dynamic, // dynamic_dispatch\n"
     << "     ::acdk::lang::dmi::StdDispatch::_invoke_static, // static_dispatch\n"
     << "     0, // count off all collectable members in this class\n"
     << "     0, // user defined info\n"
     << "     0 // next ClazzInfo in chain\n"
     << "  };\n"
     << "  static ::acdk::lang::dmi::RegisterClazzInfo _register_clazzInfo(&_clazzInfo);\n"
     << "  return &_clazzInfo;\n"
     << "};\n"
     << "static ::acdk::lang::dmi::RegisterClazzInfo _register_" << clsname << "_DmiProxy(" << clsname << "_DmiProxy::clazzInfo());\n"
     ;

}


void 
DmiProxyGeneratorExt::generateProxy(IN(RString) classname, IN(::acdk::io::RPrintWriter) out)
{
  if (classname->equals("acdk/lang/ObjectArrayBaseImpl") == true) // ## hack
    return;
  RClass cls = Class::forName(classname);
  StringBuffer sb;
  generateProxy(cls->objectClazzInfo(), sb);
  if (sb.length() > 0)
    out->println(sb.toString());
}

} // namespace mc
} // namespace tools
} // namespace acdk