2005/5/9

     
 

EnumInfo.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 "EnumInfo.h"
#include "ModuleInfo.h"

namespace acdk {
namespace tools {
namespace mc {

EnumInfo::EnumInfo(IN(RModuleInfo) module, IN(RArrayList) thenamespace, IN(RArrayList) usings, IN(RClassInfo) cls)
: CodeInfo(0, "") // ### FIXME Modifier::IsEnumInfo
, _module(module)
, _namespace(RArrayList(thenamespace->clone()))
, _usings(RArrayList(usings->clone()))
, _class(cls)
, _values(new EnumInfoValueArray(0))
, _isDefined(false)
, hasMetinfDef(false)
{
}

RString 
EnumInfo::getMetaInfoCIdentifier()
{
  return name;
}


bool 
EnumInfo::detectEnd(int tk, IN(RStreamTokenizer) in)
{
  if (tk != StreamTokenizer::TT_WORD && tk == '}')
  {
    tk = in->nextToken();
    resolveStringValues();
    return true;
  }
  return false;
}


bool 
EnumInfo::parse(IN(RStreamTokenizer) in)
{
  enum Expect
  {
    EnumName,
    Name,
    Value
  };
  Expect expect = EnumName;
  int tk;
  REnumInfoValue curValue;
  int curIntValue = 0;
  bool curIntValueDefined = true;
  while ((tk = in->nextToken()) != StreamTokenizer::TT_EOF) 
  {
    switch (expect)
    {
    case EnumName:
    {
      if (tk != StreamTokenizer::TT_WORD)
        return false;
      name = in->sval;
      tk = in->nextToken();
      if (tk == ';')
        return true;
      if (tk != '{')
        return false;
      _isDefined = true;
      expect = Name;
      break;
    }
    case Name:
    {
      if (detectEnd(tk, in) == true)
        return true;
      curValue = new EnumInfoValue(in->sval);
      expect = Value;
      break;
    }
    case Value:
    {
      if (tk == ',')
      {
        _values->append(curValue);
        expect = Name;
        break;
      }
      do {
        if (detectEnd(tk, in) == true)
        {
          _values->append(curValue);
          return true;
        }
        tk = in->nextToken();
        if (tk == ',')
        {
          _values->append(curValue);
          expect = Name;
          break;
        }
      } while (true);
      /*
      if (detectEnd(tk, in) == true)
      {
        if (curValue != Nil)
        {
          curValue->setIntValue(curIntValue);
          _values->append(curValue);
        }
        return true;
      }
      if (tk == ',')
      {
        if (curIntValueDefined == false)
          ACDK_LOG(Error, "Parsing enumeration " + name + ": Eannot determine this enumeration value: " + curValue->name);
        curValue->setIntValue(curIntValue);
        ++curIntValue;
         _values->append(curValue);
        expect = Name;
        break;
      }
      if (tk == '=')
        tk = in->nextToken();
      bool neg = false;
      if (tk == '-')
      {
        neg = true;
        tk = in->nextToken();
      }
      try {
        //curValue->setIntValue(Integer::parseInt(in->sval));
        //curIntValue = curValue->value + 1;
        curIntValueDefined = true;
      } catch (RNumberFormatException ex) {
        REnumInfoValue vi = getValue(in->sval);
        if (vi != Nil)
        {
          curValue->setIntValue(vi->value);
          curIntValueDefined = true;
        }
        else
        {
          curValue->stringValue = in->sval;
          curIntValueDefined = false;
        }
      }
      tk = in->nextToken();
      if (detectEnd(tk, in) == true)
        return true;
      expect = Name;
      // tk == ','
      */
      break;
    }
    }
  }
  return false;
}

REnumInfoValue  
EnumInfo::getValue(IN(RString) str)
{
  for (int i = 0; i < _values->length(); ++i)
  {
    if (_values[i]->name->equals(str) == true)
      return _values[i];
  }
  return Nil;
}

bool 
EnumInfo::resolveStringValues()
{
  bool ret = true;
  for (int i = 0; i < _values->length(); ++i)
  {
    if (_values[i]->stringValue != Nil && _values[i]->valueDefined == false)
    {
      REnumInfoValue v = getValue(_values[i]->stringValue);
      if (v != Nil)
        _values[i]->setIntValue(v->value);
      else
      {
        ret = false;
        ACDK_LOG(Error, "Parsing enumeration " + name + ": Cannot resolve enum value: " + _values[i]->stringValue);
      }
    }
  }
  return ret;
}

void 
EnumInfo::writeEnumInfo(IN(RPrintWriter) out)
{
  if (_isDefined == false)
    return;
  ModuleInfo::writeOpenNamespace(out, _namespace, _usings);
  int i;
  for (i = 0; i < _values->length(); ++i)
  {
    REnumInfoValue ev = _values[i];
    out->print("\n");
    out->print(RString("::acdk::lang::dmi::ClazzEnumValueInfo ") + name + "_" + ev->name + 
      " = \n{\n  ::acdk::lang::dmi::MiEnumValInfo, // flags\n  0, // attributeRes\n  \"" 
        + ev->name + "\", // name\n" 
        + "  -1, // hashCode\n"
        + "  \"\", // ns\n  0, // _scopeParent\n  0, // _nextSibling\n  "
        + "0,  // ClazzEnum definition\n  "
        + ModuleInfo::getNameSpace(_namespace, "::") + "::" + ev->name + ", // value\n"
        + "\n};\n\n"
        );
  }
  
  out->print("::acdk::lang::dmi::ClazzEnumValueInfo* " + name + "_enumValues[] = {\n");
  for (i = 0; i < _values->length(); ++i)
  {
    REnumInfoValue ev = _values[i];
    out->print("  &" + name + "_" + ev->name + ",\n");
  }
  out->print("0\n};\n\n");
  if (hasMetinfDef == true)
    out->print("::acdk::lang::dmi::ClazzEnumInfo* " + name + "MetaInf::GetEnumInfo()\n{\nstatic ");
  
  out->print("::acdk::lang::dmi::ClazzEnumInfo " + name + "_enumInfo = {\n");
  out->print("  ::acdk::lang::dmi::MiEnumInfo, // flags\n"
             "  0, // attribute rest\n");
  out->print("  \"" + name + "\", // name\n");
  out->print("  -1, // hashCode\n");
  out->print("  \"" + ModuleInfo::getNameSpace(_namespace, "/") + "\", // ns\n");
  out->print("  0, // _scopeParent\n");
  out->print("  0, // _nextSibling\n");
  out->print("  " + name + "_enumValues, // values\n");
  out->print("  0, // internal next link\n");
  out->print("};\n\n");
  if (hasMetinfDef == true)
    out->print("  static ");
  out->print("::acdk::lang::dmi::RegisterEnumInfo _register_" + name + "(&" + name + "_enumInfo);\n\n");
  if (hasMetinfDef == true)
  {
    out->print("  return &" + name + "_enumInfo;\n}\n");
    out->print("static ::acdk::lang::dmi::RegisterEnumInfo _register_" + name + "EnumInfo(" + name + "MetaInf::GetEnumInfo());\n\n");

  }
  ModuleInfo::writeCloseNamespace(out, _namespace);
}

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